From 6ba44ed546f5f8b6f3e99e34db991c8caab2239e Mon Sep 17 00:00:00 2001 From: Colton Provias Date: Wed, 20 Jan 2016 19:49:06 -0500 Subject: [PATCH] Closer to spec with dasherized names, links. Also lazy loaded relationships. --- CHANGES.md | 8 + setup.py | 2 +- sqlalchemy_jsonapi/flaskext.py | 2 +- sqlalchemy_jsonapi/serializer.py | 159 +++++++++++------- sqlalchemy_jsonapi/tests/app.py | 12 +- sqlalchemy_jsonapi/tests/conftest.py | 12 +- .../tests/test_collection_get.py | 46 ++--- .../tests/test_collection_post.py | 14 +- sqlalchemy_jsonapi/tests/test_related_get.py | 8 +- .../tests/test_relationship_delete.py | 12 +- .../tests/test_relationship_get.py | 10 +- .../tests/test_relationship_patch.py | 30 ++-- .../tests/test_relationship_post.py | 16 +- .../tests/test_resource_delete.py | 6 +- sqlalchemy_jsonapi/tests/test_resource_get.py | 30 ++-- .../tests/test_resource_patch.py | 35 ++-- sqlalchemy_jsonapi/tests/test_serializer.py | 2 +- 17 files changed, 223 insertions(+), 181 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index cd014ed..4e4ace5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,13 @@ # SQLAlchemy-JSONAPI Changelog +## 4.0.0 + +*2016-01-20* + +* BREAKING: Keys and types are now dasherized instead of underscored to fit assumptions of spec implementation +* BREAKING: Relationships are now lazy by default. Using the include query parameter will trigger an eager load. +* Added links to relationships + ## 3.0.2 *2015-10-05* diff --git a/setup.py b/setup.py index 67c9530..6c99dfc 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ requirements.append('enum34') setup(name='SQLAlchemy-JSONAPI', - version='3.0.1', + version='4.0.0', url='http://github.com/coltonprovias/sqlalchemy-jsonapi', license='MIT', author='Colton J. Provias', diff --git a/sqlalchemy_jsonapi/flaskext.py b/sqlalchemy_jsonapi/flaskext.py index 32fd4cc..94a8a9b 100644 --- a/sqlalchemy_jsonapi/flaskext.py +++ b/sqlalchemy_jsonapi/flaskext.py @@ -163,7 +163,7 @@ def _setup_adapter(self, namespace, route_prefix): :param namespace: Prefix for generated endpoints :param route_prefix: Prefix for route patterns """ - self.serializer = JSONAPI(self.sqla.Model) + self.serializer = JSONAPI(self.sqla.Model, prefix='{}://{}{}'.format(self.app.config['PREFERRED_URL_SCHEME'], self.app.config['SERVER_NAME'], route_prefix)) for view in views: method, endpoint = view pattern = route_prefix + endpoint.value diff --git a/sqlalchemy_jsonapi/serializer.py b/sqlalchemy_jsonapi/serializer.py index c5b5035..7044292 100644 --- a/sqlalchemy_jsonapi/serializer.py +++ b/sqlalchemy_jsonapi/serializer.py @@ -5,11 +5,13 @@ MIT License """ +from collections import MutableMapping from enum import Enum -from inflection import pluralize, underscore +from inflection import pluralize, dasherize, parameterize, tableize, underscore from sqlalchemy.exc import IntegrityError from sqlalchemy.orm.interfaces import MANYTOONE from sqlalchemy.util.langhelpers import iterate_attributes +from pprint import pprint from .errors import (BadRequestError, InvalidTypeForEndpointError, MissingTypeError, NotSortableError, PermissionDeniedError, @@ -138,7 +140,7 @@ def __init__(self): self.status_code = 200 self.data = { 'jsonapi': {'version': '1.0'}, - 'meta': {'sqlalchemy_jsonapi_version': '3.0.1'} + 'meta': {'sqlalchemy_jsonapi_version': '3.0.2'} } @@ -210,13 +212,15 @@ def get_rel_desc(instance, key, action): class JSONAPI(object): """ JSON API Serializer for SQLAlchemy ORM models. """ - def __init__(self, base): + def __init__(self, base, prefix=''): """ Initialize the serializer. :param base: Declarative base instance + :param namespace: The namespace of the API endpoint """ self.base = base + self.prefix = prefix self.models = {} for name, model in base._decl_class_registry.items(): if name.startswith('_'): @@ -225,12 +229,18 @@ def __init__(self, base): prepped_name = self._api_type_for_model(model) api_type = getattr(model, '__jsonapi_type_override__', prepped_name) + model_keys = set(model.__mapper__.all_orm_descriptors.keys()) + model_keys |= set(model.__mapper__.relationships.keys()) + model.__jsonapi_attribute_descriptors__ = {} 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} for prop_name, prop_value in iterate_attributes(model): + if hasattr(prop_value, '__jsonapi_desc_for_attrs__'): defaults = {'get': None, 'set': None} descriptors = model.__jsonapi_attribute_descriptors__ @@ -273,14 +283,19 @@ def __init__(self, base): self.models[model.__jsonapi_type__] = model def _api_type_for_model(self, model): - return underscore(pluralize(model.__name__)) - + return dasherize(tableize(model.__name__)) def _fetch_model(self, api_type): if api_type not in self.models.keys(): raise ResourceTypeNotFoundError(api_type) return self.models[api_type] + def _lazy_relationship(self, api_type, obj_id, rel_key): + return { + 'self': '{}/{}/{}/relationships/{}'.format(self.prefix, api_type, obj_id, rel_key), + 'related': '{}/{}/{}/{}'.format(self.prefix, api_type, obj_id, rel_key) + } + def _get_relationship(self, resource, rel_key, permission): if rel_key not in resource.__mapper__.relationships.keys(): raise RelationshipNotFoundError(resource, resource, rel_key) @@ -343,46 +358,58 @@ def _render_full_resource(self, instance, include, fields): 'included': {} } attrs_to_ignore = {'__mapper__', 'id'} - local_fields = fields.get(api_type, orm_desc_keys) + if api_type in fields.keys(): + local_fields = list(map((lambda x: instance.__jsonapi_map_to_py__[x]), fields[api_type])) + else: + local_fields = orm_desc_keys for key, relationship in instance.__mapper__.relationships.items(): attrs_to_ignore |= set([c.name for c in relationship.local_columns ]) | {key} + api_key = instance.__jsonapi_map_to_api__[key] + try: desc = get_rel_desc(instance, key, RelationshipActions.GET) except PermissionDeniedError: continue - related = desc(instance) if relationship.direction == MANYTOONE: - if related is not None: - perm = get_permission_test(related, None, Permissions.VIEW) - - if related is None or not perm(related): - if key in local_fields: - to_ret['relationships'][key] = {'data': None} + if key in local_fields: + to_ret['relationships'][api_key] = { + 'links': self._lazy_relationship(api_type, instance.id, + api_key) + } - else: + if api_key in include.keys(): + related = desc(instance) + if related is not None: + perm = get_permission_test(related, None, Permissions.VIEW) + if key in local_fields and (related is None or not perm(related)): + to_ret['relationships'][api_key]['data'] = None + continue if key in local_fields: - to_ret['relationships'][key] = { - 'data': { - 'id': related.id, - 'type': related.__jsonapi_type__ - } - } - - if key in include.keys(): - new_include = self._parse_include(include[key]) - built = self._render_full_resource(related, - new_include, fields) - included = built.pop('included') - to_ret['included'].update(included) - to_ret['included'][(related.__jsonapi_type__, related.id)] = built + to_ret['relationships'][api_key]['data'] = self._render_short_instance(related) + new_include = self._parse_include(include[api_key]) + built = self._render_full_resource(related, new_include, fields) + included = built.pop('included') + to_ret['included'].update(included) + to_ret['included'][(related.__jsonapi_type__, related.id)] = built else: + + if key in local_fields: + to_ret['relationships'][api_key] = { + 'links': self._lazy_relationship(api_type, instance.id, api_key), + } + + if api_key not in include.keys(): + continue + if key in local_fields: - to_ret['relationships'][key] = {'data': []} + to_ret['relationships'][api_key]['data'] = [] + + related = desc(instance) for item in related: try: @@ -391,24 +418,20 @@ def _render_full_resource(self, instance, include, fields): continue if key in local_fields: - to_ret['relationships'][key]['data'].append({ - 'id': item.id, - 'type': item.__jsonapi_type__ - }) - - if key in include.keys(): - new_include = self._parse_include(include[key]) - built = self._render_full_resource(item, new_include, - fields) - included = built.pop('included') - to_ret['included'].update(included) - to_ret['included'][(item.__jsonapi_type__, item.id)] = built + to_ret['relationships'][api_key]['data'].append(self._render_short_instance(item)) + + new_include = self._parse_include(include[api_key]) + built = self._render_full_resource(item, new_include, + fields) + included = built.pop('included') + to_ret['included'].update(included) + to_ret['included'][(item.__jsonapi_type__, item.id)] = built for key in set(orm_desc_keys) - attrs_to_ignore: try: desc = get_attr_desc(instance, key, AttributeActions.GET) if key in local_fields: - to_ret['attributes'][key] = desc(instance) + to_ret['attributes'][instance.__jsonapi_map_to_api__[key]] = desc(instance) except PermissionDeniedError: continue @@ -448,7 +471,7 @@ def _parse_fields(self, query): fields = {} for k, v in field_args.items(): - fields[k[7:-1]] = v + fields[k[7:-1]] = v.split(',') return fields @@ -679,7 +702,10 @@ def get_related(self, session, query, api_type, obj_id, rel_key): """ resource = self._fetch_resource(session, api_type, obj_id, Permissions.VIEW) - relationship = self._get_relationship(resource, rel_key, + if rel_key not in resource.__jsonapi_map_to_py__.keys(): + raise RelationshipNotFoundError(resource, resource, rel_key) + py_key = resource.__jsonapi_map_to_py__[rel_key] + relationship = self._get_relationship(resource, py_key, Permissions.VIEW) response = JSONAPIResponse() @@ -716,7 +742,10 @@ def get_relationship(self, session, query, api_type, obj_id, rel_key): """ resource = self._fetch_resource(session, api_type, obj_id, Permissions.VIEW) - relationship = self._get_relationship(resource, rel_key, + if rel_key not in resource.__jsonapi_map_to_py__.keys(): + raise RelationshipNotFoundError(resource, resource, rel_key) + py_key = resource.__jsonapi_map_to_py__[rel_key] + relationship = self._get_relationship(resource, py_key, Permissions.VIEW) response = JSONAPIResponse() @@ -757,7 +786,10 @@ def patch_relationship(self, session, json_data, api_type, obj_id, model = self._fetch_model(api_type) resource = self._fetch_resource(session, api_type, obj_id, Permissions.EDIT) - relationship = self._get_relationship(resource, rel_key, + if rel_key not in resource.__jsonapi_map_to_py__.keys(): + raise RelationshipNotFoundError(resource, resource, rel_key) + py_key = resource.__jsonapi_map_to_py__[rel_key] + relationship = self._get_relationship(resource, py_key, Permissions.EDIT) self._check_json_data(json_data) @@ -820,7 +852,7 @@ def patch_relationship(self, session, json_data, api_type, obj_id, raise ValidationError('Incompatible Type') return self.get_relationship(session, {}, model.__jsonapi_type__, - resource.id, relationship.key) + resource.id, rel_key) def patch_resource(self, session, json_data, api_type, obj_id): """ @@ -830,7 +862,6 @@ def patch_resource(self, session, json_data, api_type, obj_id): :param json_data: Request JSON Data :param api_type: Type of the resource :param obj_id: ID of the resource - :param rel_key: Key of the relationship to fetch """ model = self._fetch_model(api_type) resource = self._fetch_resource(session, api_type, obj_id, @@ -864,16 +895,17 @@ def patch_resource(self, session, json_data, api_type, obj_id): try: for key, relationship in resource.__mapper__.relationships.items(): + api_key = resource.__jsonapi_map_to_api__[key] attrs_to_ignore |= set(relationship.local_columns) | {key} - if key not in json_data['data']['relationships'].keys(): + if api_key not in json_data['data']['relationships'].keys(): continue self.patch_relationship( - session, json_data['data']['relationships'][key], - model.__jsonapi_type__, resource.id, key) + session, json_data['data']['relationships'][api_key], + model.__jsonapi_type__, resource.id, api_key) - data_keys = set(json_data['data']['attributes'].keys()) + data_keys = set(map((lambda x: resource.__jsonapi_map_to_py__.get(x, None)), json_data['data']['attributes'].keys())) model_keys = set(orm_desc_keys) - attrs_to_ignore if not data_keys <= model_keys: @@ -884,7 +916,7 @@ def patch_resource(self, session, json_data, api_type, obj_id): for key in data_keys & model_keys: setter = get_attr_desc(resource, key, AttributeActions.SET) - setter(resource, json_data['data']['attributes'][key]) + setter(resource, json_data['data']['attributes'][resource.__jsonapi_map_to_api__[key]]) session.commit() except IntegrityError as e: session.rollback() @@ -924,7 +956,7 @@ def post_collection(self, session, data, api_type): data['data'].setdefault('relationships', {}) data['data'].setdefault('attributes', {}) - data_keys = set(data['data']['relationships'].keys()) + data_keys = set(map((lambda x: resource.__jsonapi_map_to_py__.get(x, None)), data['data'].get('relationships', {}).keys())) model_keys = set(resource.__mapper__.relationships.keys()) if not data_keys <= model_keys: raise BadRequestError( @@ -942,9 +974,10 @@ def post_collection(self, session, data, api_type): for key, relationship in resource.__mapper__.relationships.items(): attrs_to_ignore |= set(relationship.local_columns) | {key} + py_key = resource.__jsonapi_map_to_py__[key] if 'relationships' not in data['data'].keys()\ - or key not in data['data']['relationships'].keys(): + or py_key not in data['data']['relationships'].keys(): continue data_rel = data['data']['relationships'][key] @@ -955,7 +988,7 @@ def post_collection(self, session, data, api_type): remote_side = relationship.back_populates if relationship.direction == MANYTOONE: - setter = get_rel_desc(resource, key, + setter = get_rel_desc(resource, py_key, RelationshipActions.SET) if data_rel is None: setters.append([setter, None]) @@ -978,7 +1011,7 @@ def post_collection(self, session, data, api_type): Permissions.CREATE) setters.append([setter, to_relate]) else: - setter = get_rel_desc(resource, key, + setter = get_rel_desc(resource, py_key, RelationshipActions.APPEND) if not isinstance(data_rel, list): raise BadRequestError( @@ -999,7 +1032,7 @@ def post_collection(self, session, data, api_type): Permissions.CREATE) setters.append([setter, to_relate]) - data_keys = set(data['data'].get('attributes', {}).keys()) + data_keys = set(map((lambda x: resource.__jsonapi_map_to_py__.get(x, None)), data['data'].get('attributes', {}).keys())) model_keys = set(orm_desc_keys) - attrs_to_ignore if not data_keys <= model_keys: @@ -1013,8 +1046,9 @@ def post_collection(self, session, data, api_type): setter(resource, value) for key in data_keys: + api_key = resource.__jsonapi_map_to_api__[key] setter = get_attr_desc(resource, key, AttributeActions.SET) - setter(resource, data['data']['attributes'][key]) + setter(resource, data['data']['attributes'][api_key]) session.add(resource) session.commit() @@ -1046,7 +1080,10 @@ def post_relationship(self, session, json_data, api_type, obj_id, rel_key): model = self._fetch_model(api_type) resource = self._fetch_resource(session, api_type, obj_id, Permissions.EDIT) - relationship = self._get_relationship(resource, rel_key, + if rel_key not in resource.__jsonapi_map_to_py__.keys(): + raise RelationshipNotFoundError(resource, resource, rel_key) + py_key = resource.__jsonapi_map_to_py__[rel_key] + relationship = self._get_relationship(resource, py_key, Permissions.CREATE) if relationship.direction == MANYTOONE: raise ValidationError('Cannot post to to-one relationship') @@ -1093,4 +1130,4 @@ def post_relationship(self, session, json_data, api_type, obj_id, rel_key): raise ValidationError('Incompatible type provided') return self.get_relationship( - session, {}, model.__jsonapi_type__, resource.id, relationship.key) + session, {}, model.__jsonapi_type__, resource.id, rel_key) diff --git a/sqlalchemy_jsonapi/tests/app.py b/sqlalchemy_jsonapi/tests/app.py index 301c7de..386fe75 100644 --- a/sqlalchemy_jsonapi/tests/app.py +++ b/sqlalchemy_jsonapi/tests/app.py @@ -80,7 +80,7 @@ def view_password(self): @permission_test(Permissions.EDIT) def prevent_edit(self): """ Prevent editing for no reason. """ - if request.view_args['api_type'] == 'posts': + if request.view_args['api_type'] == 'blog-posts': return True return False @@ -90,7 +90,7 @@ def allow_delete(self): return False -class Post(Timestamp, db.Model): +class BlogPost(Timestamp, db.Model): """Post model, as if this is a blog.""" __tablename__ = 'posts' @@ -124,7 +124,7 @@ def prevent_altering_of_logs(self): return False -class Comment(Timestamp, db.Model): +class BlogComment(Timestamp, db.Model): """Comment for each Post.""" __tablename__ = 'comments' @@ -134,7 +134,7 @@ class Comment(Timestamp, db.Model): author_id = Column(UUIDType, ForeignKey('users.id'), nullable=False) content = Column(UnicodeText, nullable=False) - post = relationship('Post', + post = relationship('BlogPost', lazy='joined', backref=backref('comments', lazy='dynamic')) @@ -150,7 +150,7 @@ class Log(Timestamp, db.Model): post_id = Column(UUIDType, ForeignKey('posts.id')) user_id = Column(UUIDType, ForeignKey('users.id')) - post = relationship('Post', + post = relationship('BlogPost', lazy='joined', backref=backref('logs', lazy='dynamic')) @@ -167,7 +167,7 @@ def block_interactive(cls): api = FlaskJSONAPI(app, db) -@api.wrap_handler(['posts'], [Method.GET], [Endpoint.COLLECTION]) +@api.wrap_handler(['blog-posts'], [Method.GET], [Endpoint.COLLECTION]) def sample_override(next, *args, **kwargs): return next(*args, **kwargs) diff --git a/sqlalchemy_jsonapi/tests/conftest.py b/sqlalchemy_jsonapi/tests/conftest.py index 56140b3..e028a30 100644 --- a/sqlalchemy_jsonapi/tests/conftest.py +++ b/sqlalchemy_jsonapi/tests/conftest.py @@ -12,7 +12,7 @@ from flask.testing import FlaskClient from sqlalchemy.orm import sessionmaker from app import db as db_ -from app import app, User, Post, Comment, Log +from app import app, User, BlogPost, BlogComment, Log from faker import Faker Session = sessionmaker() @@ -87,7 +87,7 @@ def user(session): @pytest.fixture def post(user, session): - new_post = Post(author=user, + new_post = BlogPost(author=user, title=fake.sentence(), content=fake.paragraph(), is_published=True) @@ -98,7 +98,7 @@ def post(user, session): @pytest.fixture def unpublished_post(user, session): - new_post = Post(author=user, + new_post = BlogPost(author=user, title=fake.sentence(), content=fake.paragraph(), is_published=False) @@ -110,19 +110,19 @@ def unpublished_post(user, session): @pytest.fixture def bunch_of_posts(user, session): for x in range(30): - new_post = Post(author=user, + new_post = BlogPost(author=user, title=fake.sentence(), content=fake.paragraph(), is_published=fake.boolean()) session.add(new_post) - new_post.comments.append(Comment(author=user, + new_post.comments.append(BlogComment(author=user, content=fake.paragraph())) session.commit() @pytest.fixture def comment(user, post, session): - new_comment = Comment(author=user, post=post, content=fake.paragraph()) + new_comment = BlogComment(author=user, post=post, content=fake.paragraph()) session.add(new_comment) session.commit() return new_comment diff --git a/sqlalchemy_jsonapi/tests/test_collection_get.py b/sqlalchemy_jsonapi/tests/test_collection_get.py index 67de78b..8442eb8 100644 --- a/sqlalchemy_jsonapi/tests/test_collection_get.py +++ b/sqlalchemy_jsonapi/tests/test_collection_get.py @@ -3,50 +3,50 @@ def test_200_with_no_querystring(bunch_of_posts, client): - response = client.get('/api/posts').validate(200) - assert response.json_data['data'][0]['type'] == 'posts' + response = client.get('/api/blog-posts').validate(200) + assert response.json_data['data'][0]['type'] == 'blog-posts' assert response.json_data['data'][0]['id'] def test_200_with_single_included_model(bunch_of_posts, client): - response = client.get('/api/posts/?include=author').validate(200) - assert response.json_data['data'][0]['type'] == 'posts' + response = client.get('/api/blog-posts/?include=author').validate(200) + assert response.json_data['data'][0]['type'] == 'blog-posts' assert response.json_data['included'][0]['type'] == 'users' def test_200_with_including_model_and_including_inbetween(bunch_of_posts, client): - response = client.get('/api/comments/?include=post.author').validate(200) - assert response.json_data['data'][0]['type'] == 'comments' + response = client.get('/api/blog-comments/?include=post.author').validate(200) + assert response.json_data['data'][0]['type'] == 'blog-comments' for data in response.json_data['included']: - assert data['type'] in ['posts', 'users'] + assert data['type'] in ['blog-posts', 'users'] def test_200_with_multiple_includes(bunch_of_posts, client): - response = client.get('/api/posts/?include=comments,author').validate(200) - assert response.json_data['data'][0]['type'] == 'posts' + response = client.get('/api/blog-posts/?include=comments,author').validate(200) + assert response.json_data['data'][0]['type'] == 'blog-posts' for data in response.json_data['included']: - assert data['type'] in ['comments', 'users'] + assert data['type'] in ['blog-comments', 'users'] def test_200_with_single_field(bunch_of_posts, client): - response = client.get('/api/posts/?fields[posts]=title').validate(200) + response = client.get('/api/blog-posts/?fields[blog-posts]=title').validate(200) for item in response.json_data['data']: assert {'title'} == set(item['attributes'].keys()) assert len(item['relationships']) == 0 def test_200_with_multiple_fields(bunch_of_posts, client): - response = client.get('/api/posts/?fields[posts]=title,content').validate( + response = client.get('/api/blog-posts/?fields[blog-posts]=title,content,is-published').validate( 200) for item in response.json_data['data']: - assert {'title', 'content'} == set(item['attributes'].keys()) + assert {'title', 'content', 'is-published'} == set(item['attributes'].keys()) assert len(item['relationships']) == 0 def test_200_with_single_field_across_a_relationship(bunch_of_posts, client): response = client.get( - '/api/posts/?fields[posts]=title,content&fields[comments]=author&include=comments').validate( + '/api/blog-posts/?fields[blog-posts]=title,content&fields[blog-comments]=author&include=comments').validate( 200) for item in response.json_data['data']: assert {'title', 'content'} == set(item['attributes'].keys()) @@ -58,48 +58,48 @@ def test_200_with_single_field_across_a_relationship(bunch_of_posts, client): def test_200_sorted_response(bunch_of_posts, client): - response = client.get('/api/posts/?sort=title').validate(200) + response = client.get('/api/blog-posts/?sort=title').validate(200) title_list = [x['attributes']['title'] for x in response.json_data['data']] assert sorted(title_list) == title_list def test_200_descending_sorted_response(bunch_of_posts, client): - response = client.get('/api/posts/?sort=-title').validate(200) + response = client.get('/api/blog-posts/?sort=-title').validate(200) title_list = [x['attributes']['title'] for x in response.json_data['data']] assert sorted(title_list, key=None, reverse=True) == title_list def test_200_sorted_response_with_multiple_criteria(bunch_of_posts, client): - response = client.get('/api/posts/?sort=title,-created').validate(200) + response = client.get('/api/blog-posts/?sort=title,-created').validate(200) title_list = [x['attributes']['title'] for x in response.json_data['data']] assert sorted(title_list, key=None, reverse=False) == title_list def test_409_when_given_relationship_for_sorting(bunch_of_posts, client): - client.get('/api/posts/?sort=author').validate(409, NotSortableError) + client.get('/api/blog-posts/?sort=author').validate(409, NotSortableError) def test_409_when_given_a_missing_field_for_sorting(bunch_of_posts, client): - client.get('/api/posts/?sort=never_gonna_give_you_up').validate( + client.get('/api/blog-posts/?sort=never_gonna_give_you_up').validate( 409, NotSortableError) def test_200_paginated_response_by_page(bunch_of_posts, client): - response = client.get('/api/posts/?page[number]=2&page[size]=5').validate( + response = client.get('/api/blog-posts/?page[number]=2&page[size]=5').validate( 200) assert len(response.json_data['data']) == 5 def test_200_paginated_response_by_offset(bunch_of_posts, client): - response = client.get('/api/posts/?page[offset]=5&page[limit]=5').validate( + response = client.get('/api/blog-posts/?page[offset]=5&page[limit]=5').validate( 200) assert len(response.json_data['data']) == 5 def test_200_when_pagination_is_out_of_range(bunch_of_posts, client): - client.get('/api/posts/?page[offset]=999999&page[limit]=5').validate(200) + client.get('/api/blog-posts/?page[offset]=999999&page[limit]=5').validate(200) def test_400_when_provided_crap_data_for_pagination(bunch_of_posts, client): - client.get('/api/posts/?page[offset]=5&page[limit]=crap').validate( + client.get('/api/blog-posts/?page[offset]=5&page[limit]=crap').validate( 400, BadRequestError) diff --git a/sqlalchemy_jsonapi/tests/test_collection_post.py b/sqlalchemy_jsonapi/tests/test_collection_post.py index cfcefc3..8dba8e2 100644 --- a/sqlalchemy_jsonapi/tests/test_collection_post.py +++ b/sqlalchemy_jsonapi/tests/test_collection_post.py @@ -32,11 +32,11 @@ def test_200_resource_creation(client): def test_200_resource_creation_with_relationships(user, client): payload = { 'data': { - 'type': 'posts', + 'type': 'blog-posts', 'attributes': { 'title': 'Some title', 'content': 'Hello, World!', - 'is_published': True + 'is-published': True }, 'relationships': { 'author': { @@ -48,13 +48,13 @@ def test_200_resource_creation_with_relationships(user, client): } } } - response = client.post('/api/posts/', + response = client.post('/api/blog-posts/', data=json.dumps(payload), content_type='application/vnd.api+json').validate( 201) - assert response.json_data['data']['type'] == 'posts' + assert response.json_data['data']['type'] == 'blog-posts' post_id = response.json_data['data']['id'] - response = client.get('/api/posts/{}/'.format(post_id)).validate(200) + response = client.get('/api/blog-posts/{}/?include=author'.format(post_id)).validate(200) assert response.json_data['data']['relationships']['author']['data'][ 'id' ] == str(user.id) @@ -87,7 +87,7 @@ def test_409_when_id_already_exists(user, client): def test_409_when_type_doesnt_match_endpoint(client): - payload = {'data': {'type': 'posts'}} + payload = {'data': {'type': 'blog-posts'}} client.post('/api/users/', data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -147,4 +147,4 @@ def test_409_for_wrong_field_name(client): client.post('/api/users/', data=json.dumps(payload), content_type='application/vnd.api+json').validate( - 400, BadRequestError) + 409, ValidationError) diff --git a/sqlalchemy_jsonapi/tests/test_related_get.py b/sqlalchemy_jsonapi/tests/test_related_get.py index d01e463..225d028 100644 --- a/sqlalchemy_jsonapi/tests/test_related_get.py +++ b/sqlalchemy_jsonapi/tests/test_related_get.py @@ -5,22 +5,22 @@ def test_200_result_of_to_one(post, client): - response = client.get('/api/posts/{}/author/'.format(post.id)).validate( + response = client.get('/api/blog-posts/{}/author/'.format(post.id)).validate( 200) assert response.json_data['data']['type'] == 'users' def test_200_collection_of_to_many(comment, client): - response = client.get('/api/posts/{}/comments/'.format( + response = client.get('/api/blog-posts/{}/comments/'.format( comment.post.id)).validate(200) assert len(response.json_data['data']) > 0 def test_404_when_relationship_not_found(post, client): - client.get('/api/posts/{}/last_comment/'.format( + client.get('/api/blog-posts/{}/last_comment/'.format( post.id)).validate(404, RelationshipNotFoundError) def test_404_when_resource_not_found(client): - client.get('/api/posts/{}/comments/'.format(uuid4())).validate( + client.get('/api/blog-posts/{}/comments/'.format(uuid4())).validate( 404, ResourceNotFoundError) diff --git a/sqlalchemy_jsonapi/tests/test_relationship_delete.py b/sqlalchemy_jsonapi/tests/test_relationship_delete.py index 7f0667b..c7ae5a8 100644 --- a/sqlalchemy_jsonapi/tests/test_relationship_delete.py +++ b/sqlalchemy_jsonapi/tests/test_relationship_delete.py @@ -8,9 +8,9 @@ def test_200_on_deletion_from_to_many(comment, client): - payload = {'data': [{'type': 'comments', 'id': str(comment.id)}]} + payload = {'data': [{'type': 'blog-comments', 'id': str(comment.id)}]} response = client.delete( - '/api/posts/{}/relationships/comments/'.format( + '/api/blog-posts/{}/relationships/comments/'.format( comment.post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate(200) @@ -22,14 +22,14 @@ def test_200_on_deletion_from_to_many(comment, client): def test_404_on_resource_not_found(client): - client.delete('/api/posts/{}/relationships/comments/'.format(uuid4()), + client.delete('/api/blog-posts/{}/relationships/comments/'.format(uuid4()), data='{}', content_type='application/vnd.api+json').validate( 404, ResourceNotFoundError) def test_404_on_relationship_not_found(post, client): - client.delete('/api/posts/{}/relationships/comment/'.format( + client.delete('/api/blog-posts/{}/relationships/comment/'.format( post.id), data='{}', content_type='application/vnd.api+json').validate( @@ -45,7 +45,7 @@ def test_403_on_permission_denied(user, client): def test_409_on_to_one_provided(post, client): - client.delete('/api/posts/{}/relationships/author/'.format( + client.delete('/api/blog-posts/{}/relationships/author/'.format( post.id), data='{"data": {}}', content_type='application/vnd.api+json').validate( @@ -53,6 +53,6 @@ def test_409_on_to_one_provided(post, client): def test_409_missing_content_type_header(post, client): - client.delete('/api/posts/{}/relationships/comment/'.format( + client.delete('/api/blog-posts/{}/relationships/comment/'.format( post.id), data='{}').validate(409, MissingContentTypeError) diff --git a/sqlalchemy_jsonapi/tests/test_relationship_get.py b/sqlalchemy_jsonapi/tests/test_relationship_get.py index 35e401f..761784c 100644 --- a/sqlalchemy_jsonapi/tests/test_relationship_get.py +++ b/sqlalchemy_jsonapi/tests/test_relationship_get.py @@ -5,7 +5,7 @@ def test_200_on_to_many(post, client): response = client.get( - '/api/posts/{}/relationships/comments/'.format( + '/api/blog-posts/{}/relationships/comments/'.format( post.id)).validate(200) for item in response.json_data['data']: assert {'id', 'type'} == set(item.keys()) @@ -13,24 +13,24 @@ def test_200_on_to_many(post, client): def test_200_on_to_one(post, client): response = client.get( - '/api/posts/{}/relationships/author/'.format( + '/api/blog-posts/{}/relationships/author/'.format( post.id)).validate(200) assert response.json_data['data']['type'] == 'users' def test_404_on_resource_not_found(client): client.get( - '/api/posts/{}/relationships/comments/'.format(uuid4())).validate( + '/api/blog-posts/{}/relationships/comments/'.format(uuid4())).validate( 404, ResourceNotFoundError) def test_404_on_relationship_not_found(post, client): client.get( - '/api/posts/{}/relationships/comment/'.format( + '/api/blog-posts/{}/relationships/comment/'.format( post.id)).validate(404, RelationshipNotFoundError) def test_403_on_permission_denied(unpublished_post, client): client.get( - '/api/posts/{}/relationships/comment/'.format( + '/api/blog-posts/{}/relationships/comment/'.format( unpublished_post.id)).validate(403, PermissionDeniedError) diff --git a/sqlalchemy_jsonapi/tests/test_relationship_patch.py b/sqlalchemy_jsonapi/tests/test_relationship_patch.py index 3496351..d1d8df5 100644 --- a/sqlalchemy_jsonapi/tests/test_relationship_patch.py +++ b/sqlalchemy_jsonapi/tests/test_relationship_patch.py @@ -9,7 +9,7 @@ def test_200_on_to_one_set_to_resource(post, user, client): payload = {'data': {'type': 'users', 'id': str(user.id)}} response = client.patch( - '/api/posts/{}/relationships/author/'.format(post.id), + '/api/blog-posts/{}/relationships/author/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate(200) assert response.json_data['data']['id'] == str(user.id) @@ -18,15 +18,15 @@ def test_200_on_to_one_set_to_resource(post, user, client): def test_200_on_to_one_set_to_null(post, client): payload = {'data': None} response = client.patch( - '/api/posts/{}/relationships/author/'.format(post.id), + '/api/blog-posts/{}/relationships/author/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate(200) assert response.json_data['data'] == None def test_200_on_to_many_set_to_resources(post, comment, client): - payload = {'data': [{'type': 'comments', 'id': str(comment.id)}]} - response = client.patch('/api/posts/{}/relationships/comments/'.format( + payload = {'data': [{'type': 'blog-comments', 'id': str(comment.id)}]} + response = client.patch('/api/blog-posts/{}/relationships/comments/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -37,7 +37,7 @@ def test_200_on_to_many_set_to_resources(post, comment, client): def test_200_on_to_many_set_to_empty(post, client): payload = {'data': []} - response = client.patch('/api/posts/{}/relationships/comments/'.format( + response = client.patch('/api/blog-posts/{}/relationships/comments/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -47,7 +47,7 @@ def test_200_on_to_many_set_to_empty(post, client): def test_409_on_to_one_set_to_empty_list(post, client): payload = {'data': []} - client.patch('/api/posts/{}/relationships/author/'.format( + client.patch('/api/blog-posts/{}/relationships/author/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -56,7 +56,7 @@ def test_409_on_to_one_set_to_empty_list(post, client): def test_409_on_to_many_set_to_null(post, client): payload = {'data': None} - client.patch('/api/posts/{}/relationships/comments/'.format( + client.patch('/api/blog-posts/{}/relationships/comments/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -64,7 +64,7 @@ def test_409_on_to_many_set_to_null(post, client): def test_404_on_resource_not_found(client): - client.patch('/api/posts/{}/relationships/comments/'.format( + client.patch('/api/blog-posts/{}/relationships/comments/'.format( uuid4()), data='{}', content_type='application/vnd.api+json').validate( @@ -72,7 +72,7 @@ def test_404_on_resource_not_found(client): def test_404_on_relationship_not_found(client, post): - client.patch('/api/posts/{}/relationships/comment/'.format( + client.patch('/api/blog-posts/{}/relationships/comment/'.format( post.id), data='{}', content_type='application/vnd.api+json').validate( @@ -80,8 +80,8 @@ def test_404_on_relationship_not_found(client, post): def test_404_on_related_item_not_found(post, client): - payload = {'data': [{'type': 'comments', 'id': str(uuid4())}]} - client.patch('/api/posts/{}/relationships/comments/'.format( + payload = {'data': [{'type': 'blog-comments', 'id': str(uuid4())}]} + client.patch('/api/blog-posts/{}/relationships/comments/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -107,8 +107,8 @@ def test_403_on_permission_denied_on_related(log, user, client): def test_409_on_to_one_with_incompatible_model(post, comment, client): - payload = {'data': {'type': 'comments', 'id': str(comment.id)}} - client.patch('/api/posts/{}/relationships/author/'.format( + payload = {'data': {'type': 'blog-comments', 'id': str(comment.id)}} + client.patch('/api/blog-posts/{}/relationships/author/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -116,8 +116,8 @@ def test_409_on_to_one_with_incompatible_model(post, comment, client): def test_409_on_to_many_with_incompatible_model(post, client): - payload = {'data': [{'type': 'posts', 'id': str(post.id)}]} - client.patch('/api/posts/{}/relationships/author/'.format( + payload = {'data': [{'type': 'blog-posts', 'id': str(post.id)}]} + client.patch('/api/blog-posts/{}/relationships/author/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( diff --git a/sqlalchemy_jsonapi/tests/test_relationship_post.py b/sqlalchemy_jsonapi/tests/test_relationship_post.py index b164ca6..287fedf 100644 --- a/sqlalchemy_jsonapi/tests/test_relationship_post.py +++ b/sqlalchemy_jsonapi/tests/test_relationship_post.py @@ -5,8 +5,8 @@ def test_200_on_to_many(comment, post, client): - payload = {'data': [{'type': 'comments', 'id': str(comment.id)}]} - response = client.post('/api/posts/{}/relationships/comments/'.format( + payload = {'data': [{'type': 'blog-comments', 'id': str(comment.id)}]} + response = client.post('/api/blog-posts/{}/relationships/comments/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -16,8 +16,8 @@ def test_200_on_to_many(comment, post, client): def test_409_on_hash_instead_of_array_provided(comment, post, client): - payload = {'data': {'type': 'comments', 'id': str(comment.id)}} - client.post('/api/posts/{}/relationships/comments/'.format( + payload = {'data': {'type': 'blog-comments', 'id': str(comment.id)}} + client.post('/api/blog-posts/{}/relationships/comments/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -26,7 +26,7 @@ def test_409_on_hash_instead_of_array_provided(comment, post, client): def test_409_on_incompatible_model(user, post, client): payload = {'data': [{'type': 'users', 'id': str(user.id)}]} - client.post('/api/posts/{}/relationships/comments/'.format( + client.post('/api/blog-posts/{}/relationships/comments/'.format( post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( @@ -35,20 +35,20 @@ def test_409_on_incompatible_model(user, post, client): def test_409_on_to_one_relationship(post, client): client.post( - '/api/posts/{}/relationships/author/'.format(post.id), + '/api/blog-posts/{}/relationships/author/'.format(post.id), data='{}', content_type='application/vnd.api+json').validate(409, ValidationError) def test_404_on_resource_not_found(client): - client.post('/api/posts/{}/relationships/comments/'.format(uuid4()), + client.post('/api/blog-posts/{}/relationships/comments/'.format(uuid4()), data='{}', content_type='application/vnd.api+json').validate( 404, ResourceNotFoundError) def test_404_on_relationship_not_found(post, client): - client.post('/api/posts/{}/relationships/comment/'.format( + client.post('/api/blog-posts/{}/relationships/comment/'.format( post.id), data='{}', content_type='application/vnd.api+json').validate( diff --git a/sqlalchemy_jsonapi/tests/test_resource_delete.py b/sqlalchemy_jsonapi/tests/test_resource_delete.py index 0ff8623..a48d429 100644 --- a/sqlalchemy_jsonapi/tests/test_resource_delete.py +++ b/sqlalchemy_jsonapi/tests/test_resource_delete.py @@ -5,8 +5,8 @@ def test_200_on_success(comment, client): - client.delete('/api/comments/{}/'.format(comment.id)).validate(204) - client.get('/api/comments/{}/'.format(comment.id)).validate( + client.delete('/api/blog-comments/{}/'.format(comment.id)).validate(204) + client.get('/api/blog-comments/{}/'.format(comment.id)).validate( 404, ResourceNotFoundError) @@ -21,5 +21,5 @@ def test_403_on_permission_denied(user, client): def test_404_on_resource_not_found(client): - client.delete('/api/comments/{}/'.format(uuid4())).validate( + client.delete('/api/blog-comments/{}/'.format(uuid4())).validate( 404, ResourceNotFoundError) diff --git a/sqlalchemy_jsonapi/tests/test_resource_get.py b/sqlalchemy_jsonapi/tests/test_resource_get.py index a3b8101..4f81414 100644 --- a/sqlalchemy_jsonapi/tests/test_resource_get.py +++ b/sqlalchemy_jsonapi/tests/test_resource_get.py @@ -3,53 +3,53 @@ def test_200_without_querystring(post, client): - response = client.get('/api/posts/{}/'.format(post.id)).validate(200) - assert response.json_data['data']['type'] == 'posts' + response = client.get('/api/blog-posts/{}/'.format(post.id)).validate(200) + assert response.json_data['data']['type'] == 'blog-posts' assert response.json_data['data']['id'] def test_404_resource_not_found(client): - client.get('/api/posts/{}/'.format(uuid4())).validate( + client.get('/api/blog-posts/{}/'.format(uuid4())).validate( 404, ResourceNotFoundError) def test_403_permission_denied(unpublished_post, client): - client.get('/api/posts/{}/'.format(unpublished_post.id)).validate( + client.get('/api/blog-posts/{}/'.format(unpublished_post.id)).validate( 403, PermissionDeniedError) def test_200_with_single_included_model(post, client): - response = client.get('/api/posts/{}/?include=author'.format( + response = client.get('/api/blog-posts/{}/?include=author'.format( post.id)).validate(200) - assert response.json_data['data']['type'] == 'posts' + assert response.json_data['data']['type'] == 'blog-posts' assert response.json_data['included'][0]['type'] == 'users' def test_200_with_including_model_and_including_inbetween(comment, client): - response = client.get('/api/comments/{}/?include=post.author'.format( + response = client.get('/api/blog-comments/{}/?include=post.author'.format( comment.id)).validate(200) - assert response.json_data['data']['type'] == 'comments' + assert response.json_data['data']['type'] == 'blog-comments' for data in response.json_data['included']: - assert data['type'] in ['posts', 'users'] + assert data['type'] in ['blog-posts', 'users'] def test_200_with_multiple_includes(post, client): - response = client.get('/api/posts/{}/?include=comments,author'.format( + response = client.get('/api/blog-posts/{}/?include=comments,author'.format( post.id)).validate(200) - assert response.json_data['data']['type'] == 'posts' + assert response.json_data['data']['type'] == 'blog-posts' for data in response.json_data['included']: - assert data['type'] in ['comments', 'users'] + assert data['type'] in ['blog-comments', 'users'] def test_200_with_single_field(post, client): - response = client.get('/api/posts/{}/?fields[posts]=title'.format( + response = client.get('/api/blog-posts/{}/?fields[blog-posts]=title'.format( post.id)).validate(200) assert {'title'} == set(response.json_data['data']['attributes'].keys()) assert len(response.json_data['data']['relationships']) == 0 def test_200_with_multiple_fields(post, client): - response = client.get('/api/posts/{}/?fields[posts]=title,content'.format( + response = client.get('/api/blog-posts/{}/?fields[blog-posts]=title,content'.format( post.id)).validate( 200) assert {'title', 'content' @@ -59,7 +59,7 @@ def test_200_with_multiple_fields(post, client): def test_200_with_single_field_across_a_relationship(post, client): response = client.get( - '/api/posts/{}/?fields[posts]=title,content&fields[comments]=author&include=comments'.format( + '/api/blog-posts/{}/?fields[blog-posts]=title,content&fields[blog-comments]=author&include=comments'.format( post.id)).validate( 200) assert {'title', 'content' diff --git a/sqlalchemy_jsonapi/tests/test_resource_patch.py b/sqlalchemy_jsonapi/tests/test_resource_patch.py index 280b1ee..e5cdac1 100644 --- a/sqlalchemy_jsonapi/tests/test_resource_patch.py +++ b/sqlalchemy_jsonapi/tests/test_resource_patch.py @@ -10,7 +10,7 @@ def test_200(client, post, user): payload = { 'data': { - 'type': 'posts', + 'type': 'blog-posts', 'id': str(post.id), 'attributes': { 'title': 'I just lost the game' @@ -25,28 +25,25 @@ def test_200(client, post, user): } } } - response = client.patch('/api/posts/{}/'.format(post.id), + response = client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( 200) assert response.json_data['data']['id'] == str(post.id) - assert response.json_data['data']['type'] == 'posts' + assert response.json_data['data']['type'] == 'blog-posts' assert response.json_data['data']['attributes']['title' ] == 'I just lost the game' - assert response.json_data['data']['relationships']['author']['data'][ - 'id' - ] == str(user.id) def test_400_missing_type(post, client): - client.patch('/api/posts/{}/'.format(post.id), + client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps({}), content_type='application/vnd.api+json').validate( 400, BadRequestError) def test_404_resource_not_found(client): - client.patch('/api/posts/{}/'.format(uuid4()), + client.patch('/api/blog-posts/{}/'.format(uuid4()), content_type='application/vnd.api+json', data='{}').validate( 404, ResourceNotFoundError) @@ -55,7 +52,7 @@ def test_404_resource_not_found(client): def test_404_related_resource_not_found(client, post): payload = { 'data': { - 'type': 'posts', + 'type': 'blog-posts', 'id': str(post.id), 'relationships': { 'author': { @@ -67,7 +64,7 @@ def test_404_related_resource_not_found(client, post): } } } - client.patch('/api/posts/{}/'.format(post.id), + client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( 404, ResourceNotFoundError) @@ -76,7 +73,7 @@ def test_404_related_resource_not_found(client, post): def test_400_field_not_found(client, post, user): payload = { 'data': { - 'type': 'posts', + 'type': 'blog-posts', 'id': str(post.id), 'relationships': { 'authors': { @@ -88,7 +85,7 @@ def test_400_field_not_found(client, post, user): } } } - client.patch('/api/posts/{}/'.format(post.id), + client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( 400, BadRequestError) @@ -97,7 +94,7 @@ def test_400_field_not_found(client, post, user): def test_409_type_mismatch_to_one(client, post, user): payload = { 'data': { - 'type': 'posts', + 'type': 'blog-posts', 'id': str(post.id), 'relationships': { 'comments': { @@ -109,7 +106,7 @@ def test_409_type_mismatch_to_one(client, post, user): } } } - client.patch('/api/posts/{}/'.format(post.id), + client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( 409, ValidationError) @@ -118,7 +115,7 @@ def test_409_type_mismatch_to_one(client, post, user): def test_400_type_mismatch_to_many(client, post, user): payload = { 'data': { - 'type': 'posts', + 'type': 'blog-posts', 'id': str(post.id), 'relationships': { 'author': [{ @@ -130,7 +127,7 @@ def test_400_type_mismatch_to_many(client, post, user): } } } - client.patch('/api/posts/{}/'.format(post.id), + client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( 400, BadRequestError) @@ -139,7 +136,7 @@ def test_400_type_mismatch_to_many(client, post, user): def test_409_validation_failed(client, post, user): payload = { 'data': { - 'type': 'posts', + 'type': 'blog-posts', 'id': str(post.id), 'attributes': { 'title': None @@ -154,7 +151,7 @@ def test_409_validation_failed(client, post, user): } } } - client.patch('/api/posts/{}/'.format(post.id), + client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( 409, ValidationError) @@ -178,7 +175,7 @@ def test_400_type_does_not_match_endpoint(client, post, user): } } } - client.patch('/api/posts/{}/'.format(post.id), + client.patch('/api/blog-posts/{}/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate( 400, BadRequestError) diff --git a/sqlalchemy_jsonapi/tests/test_serializer.py b/sqlalchemy_jsonapi/tests/test_serializer.py index 8bbe4d5..07060c9 100644 --- a/sqlalchemy_jsonapi/tests/test_serializer.py +++ b/sqlalchemy_jsonapi/tests/test_serializer.py @@ -7,5 +7,5 @@ def test_include_different_types_same_id(session, comment): comment.post.id = comment.author.id = comment.post_id = comment.author_id = new_id session.commit() - r = api.serializer.get_resource(session, {'include': 'post,author'}, 'comments', comment.id) + r = api.serializer.get_resource(session, {'include': 'post,author'}, 'blog-comments', comment.id) assert len(r.data['included']) == 2