Source code for arrested.endpoint

import json
from werkzeug.wrappers import Response

from itertools import chain

from flask import Response, abort, request, current_app
from flask.views import MethodView

from .handlers import ResponseHandler, RequestHandler


[docs]class Endpoint(MethodView): """The Endpoint class represents the HTTP methods that can be called against an Endpoint inside of a particular resource. """ #: list containing the permitted HTTP methods this endpoint accepts methods = ["GET", "POST", "PUT", "PATCH", "DELETE"] #: The name used to register this endpoint with Flask's url_map name = None #: A :class:`.ResponseHandler` class response_handler = ResponseHandler #: A :class:`.RequestHandler` class request_handler = RequestHandler #: The URL this endpoint is mapped against. This will build on top of any url_prefix #: defined at the API and Resource level url = '' #: A list of functions called before any specific request handler methods are called before_all_hooks = [] #: A list of functions called before GET requests are dispatched before_get_hooks = [] #: A list of functions called after GET requests are dispatched after_get_hooks = [] #: A list of functions called before POST requests are dispatched before_post_hooks = [] #: A list of functions called after POST requests are dispatched after_post_hooks = [] #: A list of functions called before PUT requests are dispatched before_put_hooks = [] #: A list of functions called after PUT requests are dispatched after_put_hooks = [] #: A list of functions called before PATCH requests are dispatched before_patch_hooks = [] #: A list of functions called after PATCH requests are dispatched after_patch_hooks = [] #: A list of functions called before DELETE requests are dispatched before_delete_hooks = [] #: A list of functions called after DELETE requests are dispatched after_delete_hooks = [] #: A list of functions called after all requests are dispatched after_all_hooks = []
[docs] def process_before_request_hooks(self): """Process the list of before_{method}_hooks and the before_all_hooks. The hooks will be processed in the following order 1 - any before_all_hooks defined on the :class:`arrested.ArrestedAPI` object 2 - any before_all_hooks defined on the :class:`arrested.Resource` object 3 - any before_all_hooks defined on the :class:`arrested.Endpoint` object 4 - any before_{method}_hooks defined on the :class:`arrested.Endpoint` object """ hooks = [] if self.resource: hooks.extend(self.resource.api.before_all_hooks) hooks.extend(self.resource.before_all_hooks) hooks.extend(self.before_all_hooks) hooks.extend( getattr( self, 'before_{method}_hooks'.format(method=self.meth), [] ) ) for hook in chain(hooks): hook(self)
[docs] def process_after_request_hooks(self, resp): """Process the list of before_{method}_hooks and the before_all_hooks. The hooks will be processed in the following order 1 - any after_{method}_hooks defined on the :class:`arrested.Endpoint` object 2 - any after_all_hooks defined on the :class:`arrested.Endpoint` object 2 - any after_all_hooks defined on the :class:`arrested.Resource` object 4 - any after_all_hooks defined on the :class:`arrested.ArrestedAPI` object """ hooks = [] meth_hooks = getattr( self, 'after_{method}_hooks'.format(method=self.meth), [] ) hooks.extend(meth_hooks) hooks.extend(self.after_all_hooks) if self.resource: hooks.extend(self.resource.after_all_hooks) hooks.extend(self.resource.api.after_all_hooks) for hook in chain(hooks): resp = hook(self, resp) return resp
[docs] def dispatch_request(self, *args, **kwargs): """Dispatch the incoming HTTP request to the appropriate handler. """ self.args = args self.kwargs = kwargs self.meth = request.method.lower() self.resource = current_app.blueprints.get(request.blueprint, None) if not any([self.meth in self.methods, self.meth.upper() in self.methods]): return self.return_error(405) self.process_before_request_hooks() resp = super(Endpoint, self).dispatch_request(*args, **kwargs) resp = self.make_response(resp) resp = self.process_after_request_hooks(resp) return resp
[docs] @classmethod def get_name(cls): """Returns the user provided name or the lower() class name for use when registering the Endpoint with a :class:`Resource`. :returns: registration name for this Endpoint. :rtype: string """ return cls.name or cls.__name__.lower()
[docs] def make_response(self, rv, status=200, headers=None, mime='application/json'): """Create a response object using the :class:`flask.Response` class. :param rv: Response value. If the value is not an instance of :class:`werkzeug.wrappers.Response` it will be converted into a Response object. :param status: specify the HTTP status code for this response. :param mime: Specify the mimetype for this request. :param headers: Specify dict of headers for the response. """ if not isinstance(rv, Response): resp = Response( response=rv, headers=headers, mimetype=mime, status=status ) else: resp = rv return resp
[docs] def get_response_handler_params(self, **params): """Return a dictionary of options that are passed to the specified :class:`ResponseHandler`. :returns: Dictionary of :class:`ResponseHandler` config options. :rtype: dict """ return params
[docs] def get_response_handler(self): """Return the Endpoints defined :attr:`Endpoint.response_handler`. :returns: A instance of the Endpoint specified :class:`ResonseHandler`. :rtype: :class:`ResponseHandler` """ assert self.response_handler is not None, \ 'Please define a response_handler ' \ ' for Endpoint: %s' % self.__class__.__name__ return self.response_handler(self, **self.get_response_handler_params())
[docs] def get_request_handler_params(self, **params): """Return a dictionary of options that are passed to the specified :class:`RequestHandler`. :returns: Dictionary of :class:`RequestHandler` config options. :rtype: dict """ return params
[docs] def get_request_handler(self): """Return the Endpoints defined :attr:`Endpoint.request_handler`. :returns: A instance of the Endpoint specified :class:`RequestHandler`. :rtype: :class:`RequestHandler` """ assert self.request_handler is not None, \ 'Please define a request_handler ' \ ' for Endpoint: %s' % self.__class__.__name__ return self.request_handler(self, **self.get_request_handler_params())
[docs] def return_error(self, status, payload=None): """Error handler called by request handlers when an error occurs and the request should be aborted. Usage:: def handle_post_request(self, *args, **kwargs): self.request_handler = self.get_request_handler() try: self.request_handler.process(self.get_data()) except SomeException as e: self.return_error(400, payload=self.request_handler.errors) return self.return_create_response() """ resp = None if payload is not None: payload = json.dumps(payload) resp = self.make_response(payload, status=status) if status in [405]: abort(status) else: abort(status, response=resp)
[docs] def get(self, *args, **kwargs): """Handle Incoming GET requests and dispatch to handle_get_request method. """ return self.handle_get_request()
[docs] def post(self, *args, **kwargs): """Handle Incoming POST requests and dispatch to handle_post_request method. """ return self.handle_post_request()
[docs] def put(self, *args, **kwargs): """Handle Incoming PUT requests and dispatch to handle_put_request method. """ return self.handle_put_request()
[docs] def patch(self, *args, **kwargs): """Handle Incoming PATCH requests and dispatch to handle_patch_request method. """ return self.handle_patch_request()
[docs] def delete(self, *args, **kwargs): """Handle Incoming DELETE requests and dispatch to handle_delete_request method. """ return self.handle_delete_request()