Source code for flump
"""
flump
~~~~~
An API builder which depends on Flask and Marshmallow and follows
http://jsonapi.org.
.. note:: Currently missing content negotation
(http://jsonapi.org/format/#content-negotiation-servers), possibly
to be added in a later version.
:copyright: (c) 2015 by RolePoint.
"""
import logging
from flask import Blueprint, request
from werkzeug.exceptions import MethodNotAllowed
from .error_handlers import register_error_handlers
from .methods import HttpMethods
from .orm import OrmIntegration
from .fetcher import Fetcher
from .view import FlumpView, _FlumpMethodView
from .web_utils import MIMETYPE # noqa
__version__ = "0.11.2"
__all__ = ['FlumpView', 'FlumpBlueprint', 'OrmIntegration', 'Fetcher',
'HttpMethods']
[docs]class FlumpBlueprint(Blueprint):
"""
A specialised Flask Blueprint for Marshmallow, which provides a convenience
method for registering FlumpView routes.
:param logging: If True, Provides some default logging. This logs the
request HTTP method, the kwargs passed to the view
endpoint, and the request JSON body.
Adds the 'application/vnd.api+json' Content-Type header to all responses.
"""
def __init__(self, *args, **kwargs):
super(FlumpBlueprint, self).__init__(*args, **kwargs)
register_error_handlers(self)
if kwargs.pop('logging', False):
@self.before_request
def do_logging():
logger = logging.getLogger('flump.view.{}'.format(self.name))
debug_string = (
"%s request made for resource type %s with kwargs: %s "
"and data: %s"
)
logger.debug(debug_string, request.method, request.view_args,
request.data)
[docs] def register_flump_view(self, view_class, url):
"""
Registers the various URL rules for the given `flump_view` on the
Blueprint.
:param flump_view: The :class:`.view.FlumpView` to register URLs for.
"""
flump_view = view_class()
view_func = _FlumpMethodView.as_view(
getattr(flump_view, 'VIEW_NAME', flump_view.RESOURCE_NAME),
flump_view=flump_view
)
methods = flump_view.HTTP_METHODS
# Our canonical URLs do not have a trailing slash.
# Though we use `strict_slashes=False` to make sure the route matches
# on both anyway.
url = url.rstrip('/')
url_mapping = flump_view.URL_MAPPING
def register_endpoint(flump_method, flask_method):
if flump_method in url_mapping:
func = view_func if flump_method <= methods else _meth_not_allowed
self.add_url_rule(
url_mapping[flump_method].format(url), methods=flask_method,
view_func=func, strict_slashes=False
)
register_endpoint(HttpMethods.GET, ('GET', ))
register_endpoint(HttpMethods.GET_MANY, ('GET', ))
register_endpoint(HttpMethods.POST, ('POST', ))
register_endpoint(HttpMethods.PATCH, ('PATCH', ))
register_endpoint(HttpMethods.DELETE, ('DELETE', ))
[docs] def flump_view(self, url):
"""
A class decorator for registering a flump view.
:param url: The URL to register the view under.
"""
def flump_view_decorator(view_class):
self.register_flump_view(view_class, url)
return view_class
return flump_view_decorator
def _meth_not_allowed(*args, **kwargs):
"""
We implement a function which only raises MethodNotAllowed in order to
return the correct response for methods not defined for a given flump_view.
"""
raise MethodNotAllowed