Concepts
Router
The lepo.router.Router
class is the root class of the API.
It encapsulates the OpenAPI definition document and generates the URL patterns that are to be mounted in a Django URLconf.
View Decoration
You can decorate the views that end up calling handlers when you instantiate the router.
For instance, you will need to decorate the views to be CSRF exempt if you're using Django's default CSRF middleware and need to send POST (or PATCH, etc.) requests to your API.
To do this, turn your
router.get_urls()
into
from lepo.decorators import csrf_exempt router.get_urls(decorate=(csrf_exempt,))
(Do note that this does indeed remove Django's CSRF protection from the API views.)
Handler
Handlers are the functions that do the actual API work.
They are mapped to the OpenAPI definition by way of the operationId
field available in Operation objects.
Handler functions are superficially similar to plain Django view functions aside from a few significant differences:
request
is the only positional argument passed to a handler; the other arguments are mapped from the OpenAPI operation's parameters and passed in as keyword arguments (converted tosnake_case
).
Exception Handling
You can raise a lepo.excs.ExceptionalResponse
(which wraps a Django response
)
anywhere within a handler invocation. These exceptions will be caught by the internal
PathView
class and the wrapped response used as the handler's response.
This is a pragmatic way to refactor behavior common to multiple handlers, e.g.
def _get_some_object(request, id): if not request.user.is_authenticated(): raise ExceptionalResponse(JsonResponse({'error': 'not authenticated'}, status=401)) try: return Object.objects.get(pk=id) except ObjectDoesNotExist: raise ExceptionalResponse(JsonResponse({'error': 'no such object'}, status=404)) def get_object_detail(request, id): object = _get_some_object(request, id) return {'id': object.id} def delete_object(request, id): object = _get_some_object(request, id) object.delete() return {'id': object.id, 'deleted': True}