def testPost(self): request = { u"data": { u"type": u"article", u"attributes": { u"title": u"Test entry" }, u"relationships": { u"author": { u"data": { u"id": u"1", u"type": u"person" } } } } } JsonAPIValidator.validate_jsonapi(request, True) result = self.app.post_json("/articles", params=request) self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("relationships", result.json["data"]) for key, rel in result.json["data"]["relationships"].iteritems(): self.assertIn(key, ["comments", "cover", "author", "revisions"]) self.assertIn("links", rel) self.assertIn("related", rel["links"]) self.assertIn("self", rel["links"])
def testGet(self): result = self.app.get("/articles/1") self.assertEqual(result.status, "200 OK") self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("data", result.json) # we want a single result self.assertEqual(type(result.json["data"]), type({})) self.assertIn("attributes", result.json["data"]) attributes = result.json["data"]["attributes"] self.assertEqual(attributes["title"], ARTICLE_TITLES[0]) self.assertIn("relationships", result.json["data"]) for key, rel in result.json["data"]["relationships"].iteritems(): self.assertIn(key, ["comments", "cover", "author", "revisions"]) self.assertIn("links", rel) self.assertIn("related", rel["links"]) self.assertIn("self", rel["links"]) self.assertIsInstance( result.json["data"]["relationships"]["comments"]["data"], list)
def testPatch(self): request = { u"data": { u"type": u"article", u"id": u"1", u"attributes": { u"title": u"Changed First Entry" } } } JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json("/articles/1", params=request) self.assertIn(result.status, ["202 Accepted", "200 OK", "204 No Content"]) if result.status == "204 No Content": # nothing more to test return JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertEqual(result.json["data"]["attributes"]["title"], "Changed First Entry")
def testPost(self): request = { u"data": { u"type": u"article", u"attributes": { u"title": u"Test entry" }, u"relationships": { u"author": { u"data": {u"id": u"1", u"type": u"person"} } } } } JsonAPIValidator.validate_jsonapi(request, True) result = self.app.post_json("/articles", params=request) self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("relationships", result.json["data"]) for key, rel in result.json["data"]["relationships"].iteritems(): self.assertIn(key, ["comments", "cover", "author", "revisions"]) self.assertIn("links", rel) self.assertIn("related", rel["links"]) self.assertIn("self", rel["links"])
def testList(self): result = self.app.get("/articles") self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("data", result.json) self.assertIs(len(result.json["data"]), len(ARTICLE_TITLES)) for row in result.json["data"]: self.assertEqual(row["type"], "article") self.assertIn("attributes", row) # expected attributes: title, created self.assertIs(len(row["attributes"]), 2) self.assertIn("title", row["attributes"]) self.assertIn("created", row["attributes"]) self.assertNotIn("author", row["attributes"]) self.assertIn(row["attributes"]["title"], ARTICLE_TITLES) self.assertIn("relationships", row) for key, relationship in row["relationships"].iteritems(): self.assertIn( key, ["comments", "cover", "author", "revisions"] ) self.assertIn("links", relationship) self.assertIn("related", relationship["links"]) self.assertIn("self", relationship["links"])
def testList(self): result = self.app.get("/articles") self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("data", result.json) self.assertIs(len(result.json["data"]), len(ARTICLE_TITLES)) for row in result.json["data"]: self.assertEqual(row["type"], "article") self.assertIn("attributes", row) # expected attributes: title, created self.assertIs(len(row["attributes"]), 2) self.assertIn("title", row["attributes"]) self.assertIn("created", row["attributes"]) self.assertNotIn("author", row["attributes"]) self.assertIn(row["attributes"]["title"], ARTICLE_TITLES) self.assertIn("relationships", row) for key, relationship in row["relationships"].iteritems(): self.assertIn(key, ["comments", "cover", "author", "revisions"]) self.assertIn("links", relationship) self.assertIn("related", relationship["links"]) self.assertIn("self", relationship["links"])
def testGet(self): result = self.app.get("/articles/1") self.assertEqual(result.status, "200 OK") self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("data", result.json) # we want a single result self.assertEqual(type(result.json["data"]), type({})) self.assertIn("attributes", result.json["data"]) attributes = result.json["data"]["attributes"] self.assertEqual(attributes["title"], ARTICLE_TITLES[0]) self.assertIn("relationships", result.json["data"]) for key, rel in result.json["data"]["relationships"].iteritems(): self.assertIn(key, ["comments", "cover", "author", "revisions"]) self.assertIn("links", rel) self.assertIn("related", rel["links"]) self.assertIn("self", rel["links"]) self.assertIsInstance( result.json["data"]["relationships"]["comments"]["data"], list )
def testPatch(self): request = { u"data": { u"type": u"article", u"id": u"1", u"attributes": { u"title": u"Changed First Entry" } } } JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json("/articles/1", params=request) self.assertIn( result.status, ["202 Accepted", "200 OK", "204 No Content"] ) if result.status == "204 No Content": # nothing more to test return JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertEqual( result.json["data"]["attributes"]["title"], "Changed First Entry" )
def testPatchingRelatedOneToNResourceShouldFail(self): result = self.app.get("/people/1/articles") self.assertIs(len(result.json["data"]), 2) for entry in result.json["data"]: self.assertIn(entry["attributes"]["title"], ARTICLE_TITLES) # it is not allowed to orphan an article request = { u"data": { u"id": u"1", u"type": u"person", u"relationships": { u"articles": { u"data": [] } } } } JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json("/people/1", params=request, status=400) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("orphan", result.json["errors"][0]["title"])
def testFetchingRelatedOneToNResource(self): result = self.app.get("/articles/1/comments") JsonAPIValidator.validate_jsonapi(result.json) for entry in result.json["data"]: self.assertIn(entry["attributes"]["body"], COMMENT_BODIES) self.assertEqual(entry["relationships"]["author"]["data"]["id"], "2") self.assertEqual(entry["relationships"]["article"]["data"]["id"], "1")
def testFetchingNullRelationship(self): result = self.app.get("/articles/1") rel = result.json["data"]["relationships"]["cover"]["links"]["related"] result = self.app.get(rel) JsonAPIValidator.validate_content_type(result.content_type) self.assertEqual(result.status, "200 OK") self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIsNone(result.json["data"])
def testFetchingRelatedOneToNResource(self): result = self.app.get("/articles/1/comments") JsonAPIValidator.validate_jsonapi(result.json) for entry in result.json["data"]: self.assertIn(entry["attributes"]["body"], COMMENT_BODIES) self.assertEqual( entry["relationships"]["author"]["data"]["id"], "2" ) self.assertEqual( entry["relationships"]["article"]["data"]["id"], "1" )
def testDeletingIndividualResource(self): result = self.app.get("/photos/1") JsonAPIValidator.validate_jsonapi(result.json) result = self.app.delete("/photos/1") if result.status_int not in [202, 204, 200]: warnings.warn("Delete: A server MAY respond with other HTTP status" "codes. This code is unknown to the specification.") if result.status_int == 200: JsonAPIValidator.validate_jsonapi(result.json) # the resource should be gone now self.app.get("/photos/1", status=404)
def testCreatingResourceWithMissingRequiredAttributeShouldFail(self): request = { u"data": { u"type": u"person", u"attributes": { u"name": u"Eve Bobbington" # attribute 'age' is missing } } } JsonAPIValidator.validate_jsonapi(request, True) result = self.app.post_json("/people", params=request, status=400) JsonAPIValidator.validate_content_type(result.content_type) JsonAPIValidator.validate_jsonapi(result.json)
def testUpdatingResourceRelationships(self): result = self.app.get("/articles/1") request = result.json # Person(1) is the current author self.assertEqual( result.json["data"]["relationships"]["author"]["data"]["id"], "1" ) # don't update attributes, server must ignore missing attributes del request["data"]["attributes"] # do not update the 'comments' and 'cover' relationships del request["data"]["relationships"]["comments"] del request["data"]["relationships"]["cover"] del request["data"]["relationships"]["revisions"] ptype = request["data"]["relationships"]["author"]["data"]["type"] # change author to Person(2) request["data"]["relationships"]["author"] = { u"data": { u"id": u"2", u"type": ptype } } JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json("/articles/1", params=request) result = self.app.get("/articles/1") self.assertNotEqual( result.json["data"]["relationships"]["author"]["data"]["id"], "1" ) self.assertEqual( result.json["data"]["relationships"]["author"]["data"]["id"], "2" ) self.assertEqual( result.json["data"]["attributes"]["title"], ARTICLE_TITLES[0] )
def testCreateResourceWithAlreadyExistingId(self): request = { u"data": { u"type": u"person", u"id": u"1", u"attributes": { u"name": "Jimmy Cricket", u"age": 12 } } } JsonAPIValidator.validate_jsonapi(request) # expect this to fail result = self.app.post_json("/people", params=request, status=409) JsonAPIValidator.validate_jsonapi(result.json)
def testGetRelationship(self): result = self.app.get("/articles/1") self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) result = self.app.get( result.json["data"]["relationships"]["author"]["links"]["self"]) self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("data", result.json) self.assertIsInstance(result.json["data"], dict) self.assertEqual(result.json["data"]["type"], "person") self.assertEqual(result.json["data"]["id"], "1")
def testCreatingResourceWithReferences(self): request = { u"data": { u"type": u"photo", u"attributes": { u"title": u"Ember Hamster", u"src": u"http://example.com/images/productivity.png" }, u"relationships": { u"photographer": { u"data": { u"type": u"people", u"id": u"2" } } } } } JsonAPIValidator.validate_jsonapi(request, True) result = self.app.post_json("/photos", params=request) JsonAPIValidator.validate_content_type(result.content_type) JsonAPIValidator.validate_jsonapi(result.json) if not result.location: warnings.warn( "The response SHOULD include a Location header identifying the" "location of the newly created resource.") else: res = self.app.get(result.location) self.assertIsNotNone(res.json) JsonAPIValidator.validate_jsonapi(res.json)
def testCreatingResourceWithReferences(self): request = { u"data": { u"type": u"photo", u"attributes": { u"title": u"Ember Hamster", u"src": u"http://example.com/images/productivity.png" }, u"relationships": { u"photographer": { u"data": {u"type": u"people", u"id": u"2"} } } } } JsonAPIValidator.validate_jsonapi(request, True) result = self.app.post_json("/photos", params=request) JsonAPIValidator.validate_content_type(result.content_type) JsonAPIValidator.validate_jsonapi(result.json) if not result.location: warnings.warn( "The response SHOULD include a Location header identifying the" "location of the newly created resource." ) else: res = self.app.get(result.location) self.assertIsNotNone(res.json) JsonAPIValidator.validate_jsonapi(res.json)
def testPatchRelationship(self): result = self.app.get("/articles/1") self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) rel = result.json["data"]["relationships"]["author"]["links"]["self"] request = { u"data": {u"type": u"person", u"id": u"2"} } JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json(rel, params=request) self.assertIn( result.status, ["200 OK", "202 Accepted", "204 No Content"] ) if result.status == "204 No Content": self.assertIs(len(result.body), 0) elif result.status == "200 OK": self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json)
def testPatchingRelatedOneToNResourceShouldSucceed(self): result = self.app.get("/articles/2/cover") self.assertIsInstance(result.json["data"], dict) request = { u"data": { u"id": u"2", u"type": u"article", u"relationships": { u"cover": { u"data": None } } } } JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json("/articles/2", params=request) result = self.app.get("/articles/2/cover") self.assertIsNone(result.json["data"])
def testFetchingDataCollection(self): result = self.app.get("/articles") JsonAPIValidator.validate_content_type(result.content_type) self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_jsonapi(result.json) self.assertIs(len(result.json["data"]), 2) for entry in result.json["data"]: self.assertEqual(entry["type"], "article") self.assertIsInstance(entry["id"], unicode) self.assertIn(entry["attributes"]["title"], ARTICLE_TITLES) Article.delete().where(True).execute() result = self.app.get("/articles") JsonAPIValidator.validate_content_type(result.content_type) self.assertEqual(result.status, "200 OK") self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIs(len(result.json["data"]), 0)
def testGetRelationship(self): result = self.app.get("/articles/1") self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) result = self.app.get( result.json["data"]["relationships"]["author"]["links"]["self"] ) self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) self.assertIn("data", result.json) self.assertIsInstance(result.json["data"], dict) self.assertEqual(result.json["data"]["type"], "person") self.assertEqual(result.json["data"]["id"], "1")
def testUpdatingResourceRelationships(self): result = self.app.get("/articles/1") request = result.json # Person(1) is the current author self.assertEqual( result.json["data"]["relationships"]["author"]["data"]["id"], "1") # don't update attributes, server must ignore missing attributes del request["data"]["attributes"] # do not update the 'comments' and 'cover' relationships del request["data"]["relationships"]["comments"] del request["data"]["relationships"]["cover"] del request["data"]["relationships"]["revisions"] ptype = request["data"]["relationships"]["author"]["data"]["type"] # change author to Person(2) request["data"]["relationships"]["author"] = { u"data": { u"id": u"2", u"type": ptype } } JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json("/articles/1", params=request) result = self.app.get("/articles/1") self.assertNotEqual( result.json["data"]["relationships"]["author"]["data"]["id"], "1") self.assertEqual( result.json["data"]["relationships"]["author"]["data"]["id"], "2") self.assertEqual(result.json["data"]["attributes"]["title"], ARTICLE_TITLES[0])
def testUpdatingResourceViaSelfLink(self): UPDATE_TITLE = u"Five Ways You Have Never Tried To Access Your Data" result = self.app.get("/articles/1") update_uri = result.json["data"]["links"]["self"] request = { u"data": { u"type": u"article", u"id": u"1", u"attributes": { u"title": UPDATE_TITLE } } } JsonAPIValidator.validate_jsonapi(request) res = self.app.patch_json(update_uri, params=request) if "204" not in res.status: JsonAPIValidator.validate_content_type(res.content_type) res = self.app.get("/articles/1") self.assertEqual(res.json["data"]["attributes"]["title"], UPDATE_TITLE)
def testPatchRelationship(self): result = self.app.get("/articles/1") self.assertEqual(result.status, "200 OK") JsonAPIValidator.validate_content_type(result.content_type) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json) rel = result.json["data"]["relationships"]["author"]["links"]["self"] request = {u"data": {u"type": u"person", u"id": u"2"}} JsonAPIValidator.validate_jsonapi(request) result = self.app.patch_json(rel, params=request) self.assertIn(result.status, ["200 OK", "202 Accepted", "204 No Content"]) if result.status == "204 No Content": self.assertIs(len(result.body), 0) elif result.status == "200 OK": self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json)
def testFetchingMissingSingleResource(self): result = self.app.get("/article/1337", status=404) self.assertIsNotNone(result.json) JsonAPIValidator.validate_jsonapi(result.json)
def testListingRelatedOneToNResource(self): result = self.app.get("/articles/1/relationships/comments") JsonAPIValidator.validate_jsonapi(result.json) for entry in result.json["data"]: JsonAPIValidator.validate_resource_identifier(entry)