Skip to content

Commit

Permalink
Merge pull request #25 from rolepoint/feature/include-etag-in-body
Browse files Browse the repository at this point in the history
Include etag in `meta` section of each entities `data`
  • Loading branch information
carlos-alberto committed May 11, 2016
2 parents 7b03c75 + adc7275 commit 1bd9d3a
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 28 deletions.
6 changes: 4 additions & 2 deletions flump/methods/get_many.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from flask import jsonify, request

from ..schemas import EntityData, make_response_schema, ManyResponseData
from ..schemas import (
EntityData, make_response_schema, ManyResponseData, EntityMetaData
)


class GetMany:
Expand Down Expand Up @@ -29,7 +31,7 @@ def get_many(self, **kwargs):
entities to be returned.
"""
entities = [
EntityData(i.id, self.RESOURCE_NAME, i)
EntityData(i.id, self.RESOURCE_NAME, i, EntityMetaData(i.etag))
for i in self.get_many_entities(**kwargs)
]
data = self._make_get_many_response(entities, **kwargs)
Expand Down
5 changes: 3 additions & 2 deletions flump/methods/get_single.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from werkzeug.exceptions import NotFound

from ..schemas import EntityData, ResponseData
from ..schemas import EntityData, ResponseData, EntityMetaData


class GetSingle:
Expand All @@ -28,7 +28,8 @@ def get_single(self, entity_id, **kwargs):
if self._etag_matches(entity):
return '', 304

entity_data = EntityData(entity.id, self.RESOURCE_NAME, entity)
entity_data = EntityData(entity.id, self.RESOURCE_NAME,
entity, EntityMetaData(entity.etag))
response_data, _ = self.response_schema(strict=True).dump(
ResponseData(entity_data, {'self': request.url})
)
Expand Down
10 changes: 6 additions & 4 deletions flump/methods/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from werkzeug.exceptions import NotFound

from ..exceptions import FlumpUnprocessableEntity
from ..schemas import ResponseData, make_entity_schema, make_data_schema
from ..schemas import (
ResponseData, make_entity_schema, make_data_schema, EntityMetaData
)
from ..web_utils import get_json


Expand Down Expand Up @@ -65,9 +67,9 @@ def patch(self, entity_id, **kwargs):
raise FlumpUnprocessableEntity(errors=errors)

entity = self.update_entity(entity, entity_data.attributes)

response_data = ResponseData(entity_data._replace(attributes=entity),
{'self': request.url})
entity_data = entity_data._replace(attributes=entity,
meta=EntityMetaData(entity.etag))
response_data = ResponseData(entity_data, {'self': request.url})

data, _ = self.response_schema(strict=True).dump(response_data)
response = jsonify(data)
Expand Down
13 changes: 10 additions & 3 deletions flump/methods/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@


from ..exceptions import FlumpUnprocessableEntity
from ..schemas import ResponseData, make_entity_schema, make_data_schema
from ..schemas import (
ResponseData, make_entity_schema, make_data_schema, EntityMetaData
)
from ..web_utils import url_for, get_json


Expand Down Expand Up @@ -62,10 +64,15 @@ def post(self, **kwargs):
entity_id=entity_data.attributes.id, _method='GET',
**kwargs)
schema = self.response_schema(strict=True)
response_data = ResponseData(entity_data, {'self': url})

etag = entity_data.attributes.etag
response_data = ResponseData(
entity_data._replace(meta=EntityMetaData(etag)),
{'self': url}
)
data, _ = schema.dump(response_data)

response = jsonify(data)
response.headers['Location'] = url
response.set_etag(str(entity_data.attributes.etag))
response.set_etag(str(etag))
return response, 201
12 changes: 10 additions & 2 deletions flump/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@
from .exceptions import FlumpUnprocessableEntity


EntityData = namedtuple('EntityData', ('id', 'type', 'attributes'))
EntityData = namedtuple('EntityData', ('id', 'type', 'attributes', 'meta'))

ResponseData = namedtuple('ResponseData', ('data', 'links'))

EntityMetaData = namedtuple('EntityMetaData', ('etag'))

ManyResponseData = namedtuple('ManyResponseData', ('data', 'links', 'meta'))


class EntityMetaSchema(Schema):
etag = fields.Str(dump_only=True)


def make_data_schema(
resource_schema, only=None, partial=False, id_required=False
):
Expand All @@ -37,6 +43,7 @@ class JsonApiSchema(Schema):
type = fields.Str(required=True)
attributes = fields.Nested(resource_schema,
required=True, only=only, partial=partial)
meta = fields.Nested(EntityMetaSchema, dump_only=True)

@post_load
def to_entity_data(self, data):
Expand All @@ -45,7 +52,8 @@ def to_entity_data(self, data):
namedtuple format. When loading we do not have an ID so this
will be None.
"""
return EntityData(data.get('id'), data['type'], data['attributes'])
return EntityData(data.get('id'), data['type'],
data['attributes'], None)

@pre_dump
def add_id_to_schema(self, entity_data):
Expand Down
19 changes: 10 additions & 9 deletions test/methods/test_get_many.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from mock import ANY
import pytest

from flump.web_utils import url_for
Expand All @@ -20,15 +21,15 @@ def test_get_many(self, flask_client):
'data': [
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '1', 'type': 'user'
'id': '1', 'type': 'user', 'meta': {'etag': ANY}
},
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '2', 'type': 'user'
'id': '2', 'type': 'user', 'meta': {'etag': ANY}
},
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '3', 'type': 'user'
'id': '3', 'type': 'user', 'meta': {'etag': ANY}
}
],
'links': {'self': 'http://localhost/tester/user/'}
Expand Down Expand Up @@ -80,11 +81,11 @@ def test_get_many(self, flask_client):
'data': [
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '1', 'type': 'user'
'id': '1', 'type': 'user', 'meta': {'etag': ANY}
},
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '2', 'type': 'user'
'id': '2', 'type': 'user', 'meta': {'etag': ANY}
}
],
'links': {
Expand All @@ -104,7 +105,7 @@ def test_get_many(self, flask_client):
'data': [
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '3', 'type': 'user'
'id': '3', 'type': 'user', 'meta': {'etag': ANY}
}
],
'links': {
Expand Down Expand Up @@ -133,15 +134,15 @@ def test_get_many_uses_query_string(self, flask_client):
'data': [
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '4', 'type': 'user'
'id': '4', 'type': 'user', 'meta': {'etag': ANY}
},
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '5', 'type': 'user'
'id': '5', 'type': 'user', 'meta': {'etag': ANY}
},
{
'attributes': {'name': 'Carl', 'age': 26},
'id': '6', 'type': 'user'
'id': '6', 'type': 'user', 'meta': {'etag': ANY}
}
],
'links': {
Expand Down
4 changes: 3 additions & 1 deletion test/methods/test_get_single.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from mock import ANY

from ..helpers import create_user, get_user


Expand All @@ -8,7 +10,7 @@ def test_get(flask_client):
assert response.json == {
'data': {
'attributes': {'name': 'Carl', 'age': 26},
'id': '1', 'type': 'user'
'id': '1', 'type': 'user', 'meta': {'etag': ANY}
},
'links': {'self': 'http://localhost/tester/user/1'}
}
Expand Down
8 changes: 5 additions & 3 deletions test/methods/test_patch.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from mock import ANY

from ..helpers import create_user, patch_user


Expand All @@ -12,7 +14,7 @@ def test_patch(flask_client):
assert response.json == {
'data': {
'attributes': {'name': 'Carly', 'age': 27},
'id': '1', 'type': 'user'
'id': '1', 'type': 'user', 'meta': {'etag': ANY}
},
'links': {'self': 'http://localhost/tester/user/1'}
}
Expand Down Expand Up @@ -44,7 +46,7 @@ def test_patch_updates_only_specified_field(flask_client):
assert response.json == {
'data': {
'attributes': {'name': 'Carly', 'age': 26},
'id': '1', 'type': 'user'
'id': '1', 'type': 'user', 'meta': {'etag': ANY}
},
'links': {'self': 'http://localhost/tester/user/1'}
}
Expand Down Expand Up @@ -72,7 +74,7 @@ def test_patch_works_with_wildcard_etag(flask_client):
assert response.json == {
'data': {
'attributes': {'name': 'Carly', 'age': 27},
'id': '1', 'type': 'user'
'id': '1', 'type': 'user', 'meta': {'etag': ANY}
},
'links': {'self': 'http://localhost/tester/user/1'}
}
Expand Down
3 changes: 2 additions & 1 deletion test/methods/test_post.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from flump.web_utils import url_for
from mock import ANY

from ..helpers import create_user

Expand All @@ -9,7 +10,7 @@ def test_post(flask_client):
assert response.json == {
'data': {
'attributes': {'name': 'Carl', 'age': 26},
'type': 'user', 'id': '1'
'type': 'user', 'id': '1', 'meta': {'etag': ANY}
},
'links': {'self': 'http://localhost/tester/user/1'}
}
Expand Down
4 changes: 3 additions & 1 deletion test/test_validators.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from marshmallow import fields
from mock import ANY
import pytest

from flump.validators import Immutable
Expand Down Expand Up @@ -51,7 +52,8 @@ def test_patch_does_not_enforce_name_being_present(self, flask_client):
'data': {
'attributes': {'age': 99, 'name': 'Carl'},
'id': '1',
'type': 'user'
'type': 'user',
'meta': {'etag': ANY}
},
'links': {'self': 'http://localhost/tester/user/1'}
}
Expand Down

0 comments on commit 1bd9d3a

Please sign in to comment.