New setting DDP_API_ENDPOINT_DECORATORS.

Takes a list of dotted import paths to decorators which are applied to API
endpoints.  For example, enable New Relic instrumentation with the following:

```
DDP_API_ENDPOINT_DECORATORS = ['newrelic.agent.background_task']
```
This commit is contained in:
Tyson Clugg 2015-10-13 11:05:02 +11:00
parent 397e044ddd
commit b14b2a427e

View file

@ -21,6 +21,7 @@ except ImportError:
from django.db.models import Expression as ExpressionNode
from django.db.models.sql import aggregates as sql_aggregates
from django.utils.encoding import force_text
from django.utils.module_loading import import_string
from django.db import DatabaseError
from django.db.models import signals
import ejson
@ -34,6 +35,12 @@ from dddp.models import (
)
API_ENDPOINT_DECORATORS = [
import_string(dotted_path)
for dotted_path
in getattr(settings, 'DDP_API_ENDPOINT_DECORATORS', [])
]
XMIN = {'select': {'xmin': "'xmin'"}}
@ -88,16 +95,54 @@ class Array(aggregates.Aggregate):
return value
def api_endpoint(path_or_func):
"""Decorator to mark a method as an API endpoint for later registration."""
def api_endpoint(path_or_func=None, decorate=True):
"""
Decorator to mark a method as an API endpoint for later registration.
Args:
path_or_func: either the function to be decorated or its API path.
decorate (bool): Apply API_ENDPOINT_DECORATORS if True (default).
Returns:
Callable: Decorated function (with optionally applied decorators).
Examples:
>>> class Counter(APIMixin):
... value = 0
...
... # default API path matches function name 'increment'.
... @api_endpoint
... def increment(self, amount):
... '''Increment counter value by `amount`.'''
... self.value += amount
... return self.value
...
... # excplicitly set API path to 'Decrement'.
... @api_endpoint('Decrement')
... def decrement(self, amount):
... '''Decrement counter value by `amount`.'''
... self.value -= amount
... return self.value
"""
def maybe_decorated(func):
"""Apply API_ENDPOINT_DECORATORS to func."""
if decorate:
for decorator in API_ENDPOINT_DECORATORS:
func = decorator()(func)
return func
if callable(path_or_func):
path_or_func.api_path = path_or_func.__name__
return path_or_func
return maybe_decorated(path_or_func)
else:
def _api_endpoint(func):
"""Decorator inner."""
func.api_path = path_or_func
return func
if path_or_func is None:
func.api_path = func.__name__
else:
func.api_path = path_or_func
return maybe_decorated(func)
return _api_endpoint
@ -675,7 +720,7 @@ class DDP(APIMixin):
if not silent:
this.send({'msg': 'nosub', 'id': id_})
@api_endpoint
@api_endpoint(decorate=False)
def method(self, method, params, id_):
"""Invoke a method."""
try: