Use Cornice for REST API viws

still very experimental at this point
This commit is contained in:
Lance Edgar 2018-11-03 17:13:08 -05:00
parent 31ae5eacd5
commit ad35481234
5 changed files with 51 additions and 52 deletions

View file

@ -28,9 +28,12 @@ from __future__ import unicode_literals, absolute_import
from rattail.db import model
from cornice.resource import resource
from tailbone.api import APIMasterView
@resource(collection_path='/api/customers', path='/api/customer/{uuid}')
class CustomerView(APIMasterView):
model_class = model.Customer
@ -43,4 +46,4 @@ class CustomerView(APIMasterView):
def includeme(config):
CustomerView.defaults(config)
config.scan(__name__)

View file

@ -33,6 +33,15 @@ from tailbone.db import Session
class APIMasterView(APIView):
"""
Base class for data model REST API views.
"""
allow_get = True
allow_collection_get = True
@property
def Session(self):
return Session
@classmethod
def get_model_class(cls):
@ -41,48 +50,34 @@ class APIMasterView(APIView):
raise NotImplementedError("must set `model_class` for {}".format(cls.__name__))
@classmethod
def get_model_key(cls):
if hasattr(cls, 'model_key'):
return cls.model_name
def get_normalized_model_name(cls):
if hasattr(cls, 'normalized_model_name'):
return cls.normalized_model_name
return cls.get_model_class().__name__.lower()
@classmethod
def get_model_key_plural(cls):
if hasattr(cls, 'model_key_plural'):
return cls.model_key_plural
return '{}s'.format(cls.get_model_key())
def get_object_key(cls):
if hasattr(cls, 'object_key'):
return cls.object_key
return cls.get_normalized_model_name()
# raise NotImplementedError("must set `object_key` for {}".format(cls.__name__))
@classmethod
def get_route_prefix(cls):
if hasattr(cls, 'route_prefix'):
return cls.route_prefix
return 'api.{}'.format(cls.get_model_key_plural())
def get_collection_key(cls):
if hasattr(cls, 'collection_key'):
return cls.collection_key
return '{}s'.format(cls.get_object_key())
# raise NotImplementedError("must set `collection_key` for {}".format(cls.__name__))
@classmethod
def get_permission_prefix(cls):
if hasattr(cls, 'permission_prefix'):
return cls.permission_prefix
return cls.get_model_key_plural()
@classmethod
def get_url_prefix(cls):
if hasattr(cls, 'url_prefix'):
return cls.url_prefix
return '/api/{}'.format(cls.get_model_key_plural())
@property
def Session(self):
return Session
@api
def index(self):
objects = self.Session.query(self.model_class)
def collection_get(self):
cls = self.get_model_class()
objects = self.Session.query(cls)
sort = self.request.params.get('sort')
if sort:
# TODO: this is fragile, but what to do if bad params?
sortkey, sortdir = sort.split('|')
sortkey = getattr(self.model_class, sortkey)
sortkey = getattr(cls, sortkey)
objects = objects.order_by(getattr(sortkey, sortdir)())
# NOTE: we only page results if sorting is in effect, otherwise
@ -94,19 +89,12 @@ class APIMasterView(APIView):
per_page = int(per_page)
objects = SqlalchemyOrmPage(objects, items_per_page=per_page, page=page)
data = [self.normalize(obj) for obj in objects]
return data
objects = [self.normalize(obj) for obj in objects]
return {self.get_collection_key(): objects}
def normalize(self, obj):
raise NotImplementedError("must implement `normalize()` method for: {}".format(self.__class__.__name__))
@classmethod
def defaults(cls, config):
route_prefix = cls.get_route_prefix()
url_prefix = cls.get_url_prefix()
permission_prefix = cls.get_permission_prefix()
# index
config.add_route(route_prefix, '{}/'.format(url_prefix), request_method='GET')
config.add_view(cls, attr='index', route_name=route_prefix,
renderer='json', permission='{}.list'.format(permission_prefix))
def get(self):
uuid = self.request.matchdict['uuid']
obj = self.Session.query(self.get_model_class()).get(uuid)
if not obj:
raise self.notfound()
return {self.get_object_key(): self.normalize(obj)}

View file

@ -30,11 +30,16 @@ import six
from rattail.db import model
from cornice.resource import resource
from tailbone.api import APIMasterView
class UpgradeView(APIMasterView):
@resource(collection_path='/api/upgrades', path='/api/upgrades/{uuid}')
class UpgradeAPIView(APIMasterView):
"""
REST API views for Upgrade model.
"""
model_class = model.Upgrade
def normalize(self, upgrade):
@ -54,4 +59,4 @@ class UpgradeView(APIMasterView):
def includeme(config):
UpgradeView.defaults(config)
config.scan(__name__)

View file

@ -30,9 +30,12 @@ import six
from rattail.db import model
from cornice.resource import resource
from tailbone.api import APIMasterView
@resource(collection_path='/api/users', path='/api/users/{uuid}')
class UserView(APIMasterView):
model_class = model.User
@ -45,4 +48,4 @@ class UserView(APIMasterView):
def includeme(config):
UserView.defaults(config)
config.scan(__name__)

View file

@ -46,7 +46,7 @@ class View(object):
Base class for all class-based views.
"""
def __init__(self, request):
def __init__(self, request, context=None):
self.request = request
# if user becomes inactive while logged in, log them out