Skip to content

Commit

Permalink
Make the dasherize behavior optional
Browse files Browse the repository at this point in the history
The spec doesn't require it, although it is recommended.
I personally don't want the behavior because I want
my client attributes to match those in the database.

Fixes ColtonProvias#24
  • Loading branch information
Greg Hill committed Aug 28, 2016
1 parent 17b8e48 commit d24cb42
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 12 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ api = FlaskJSONAPI(app, db)
# Or, for factory-style applications
api = FlaskJSONAPI()
api.init_app(app, db)

# To disable using hyphens as word-separators, disable the dasherize option
api = FlaskJSONAPI(app, db, options={'dasherize': False})
```

## Quick usage without Flask
Expand All @@ -38,4 +41,4 @@ api = JSONAPI(Base)

# And assuming a SQLAlchemy session
print(api.get_collection(session, {}, 'resource-type'))
```
```
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
requirements.append('enum34')

setup(name='SQLAlchemy-JSONAPI',
version='4.0.9',
version='4.0.10',
url='http://github.com/coltonprovias/sqlalchemy-jsonapi',
license='MIT',
author='Colton J. Provias',
Expand Down
18 changes: 12 additions & 6 deletions sqlalchemy_jsonapi/flaskext.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ def __init__(self,
app=None,
sqla=None,
namespace='api',
route_prefix='/api'):
route_prefix='/api',
options=None):
"""
Initialize the adapter. If app isn't passed here, it should be passed
in init_app.
Expand All @@ -100,9 +101,10 @@ def __init__(self,
self._handler_chains = dict()

if app is not None:
self._setup_adapter(namespace, route_prefix)
self._setup_adapter(namespace, route_prefix, options=options)

def init_app(self, app, sqla, namespace='api', route_prefix='/api'):
def init_app(self, app, sqla, namespace='api', route_prefix='/api',
options=None):
"""
Initialize the adapter if it hasn't already been initialized.
Expand All @@ -114,7 +116,7 @@ def init_app(self, app, sqla, namespace='api', route_prefix='/api'):
self.app = app
self.sqla = sqla

self._setup_adapter(namespace, route_prefix)
self._setup_adapter(namespace, route_prefix, options=options)

def wrap_handler(self, api_types, methods, endpoints):
"""
Expand Down Expand Up @@ -156,14 +158,18 @@ def wrapped(*args, **kwargs):

return wrapped

def _setup_adapter(self, namespace, route_prefix):
def _setup_adapter(self, namespace, route_prefix, options=None):
"""
Initialize the serializer and loop through the views to generate them.
:param namespace: Prefix for generated endpoints
:param route_prefix: Prefix for route patterns
"""
self.serializer = JSONAPI(self.sqla.Model, prefix='{}://{}{}'.format(self.app.config['PREFERRED_URL_SCHEME'], self.app.config['SERVER_NAME'], route_prefix))
self.serializer = JSONAPI(self.sqla.Model,
prefix='{}://{}{}'.format(self.app.config['PREFERRED_URL_SCHEME'],
self.app.config['SERVER_NAME'],
route_prefix),
options=options)
for view in views:
method, endpoint = view
pattern = route_prefix + endpoint.value
Expand Down
24 changes: 20 additions & 4 deletions sqlalchemy_jsonapi/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,16 +212,27 @@ def get_rel_desc(instance, key, action):
class JSONAPI(object):
""" JSON API Serializer for SQLAlchemy ORM models. """

def __init__(self, base, prefix=''):
default_options = {
'dasherize': True,
}

def __init__(self, base, prefix='', options=None):
"""
Initialize the serializer.
:param base: Declarative base instance
:param namespace: The namespace of the API endpoint
:param options: an options dict (refer to `JSONAPI.default_options`
for available settings and their defaults)
"""

self.base = base
self.prefix = prefix
self.models = {}
self.options = dict(**self.default_options)
if options:
self.options.update(options)

for name, model in base._decl_class_registry.items():
if name.startswith('_'):
continue
Expand All @@ -236,8 +247,8 @@ def __init__(self, base, prefix=''):
model.__jsonapi_rel_desc__ = {}
model.__jsonapi_permissions__ = {}
model.__jsonapi_type__ = api_type
model.__jsonapi_map_to_py__ = {dasherize(underscore(x)): x for x in model_keys}
model.__jsonapi_map_to_api__ = {x: dasherize(underscore(x)) for x in model_keys}
model.__jsonapi_map_to_py__ = {self._dasherize(underscore(x)): x for x in model_keys}
model.__jsonapi_map_to_api__ = {x: self._dasherize(underscore(x)) for x in model_keys}

for prop_name, prop_value in iterate_attributes(model):

Expand Down Expand Up @@ -282,8 +293,13 @@ def __init__(self, base, prefix=''):
perm_idv[check_perm] = prop_value
self.models[model.__jsonapi_type__] = model

def _dasherize(self, word):
if self.options.get('dasherize', True):
return dasherize(word)
return word

def _api_type_for_model(self, model):
return dasherize(tableize(model.__name__))
return self._dasherize(tableize(model.__name__))

def _fetch_model(self, api_type):
if api_type not in self.models.keys():
Expand Down
11 changes: 11 additions & 0 deletions sqlalchemy_jsonapi/tests/test_serializer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from app import api
from sqlalchemy_jsonapi import JSONAPI
import uuid


Expand All @@ -9,3 +10,13 @@ def test_include_different_types_same_id(session, comment):

r = api.serializer.get_resource(session, {'include': 'post,author'}, 'blog-comments', comment.id)
assert len(r.data['included']) == 2


def test_no_dasherize(session, comment):
api.serializer = JSONAPI(api.serializer.base, api.serializer.prefix,
options={'dasherize': False})

r = api.serializer.get_resource(session, {}, 'blog_comments', comment.id)
assert r.data['data']['type'] == 'blog_comments'

api.serializer = JSONAPI(api.serializer.base, api.serializer.prefix)

0 comments on commit d24cb42

Please sign in to comment.