Read¶
Prerequisite to test following examples is to have an API key with permissions:
Path | Methods | ACL |
---|---|---|
/resources/news\.article | POST | off |
/resources/news\.article/[0-9a-fA-F]{24} | GET | off |
/resources/news\.article/[0-9a-fA-F]{24}/relationships/similar | GET | off |
/resources/news\.article/[0-9a-fA-F]{24}/similar | GET | off |
/resources/writer | POST | off |
/resources/writer/[0-9a-fA-F]{24} | GET | off |
/users/core\.user | POST | off |
/users/core\.user\.token | POST | off |
/resources/note | POST | on |
/resources/note\.acl/[0-9a-fA-F]{24} | GET | on |
/resources/note\.acl\.acl/[0-9a-fA-F]{24} | GET | on |
Document¶
Create a document using API request:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "news.article",
"attributes": {
"title": "What makes world go round"
}
}
}' \
-X POST https://api.jazer.io/resources/news.article
The response contains a created document which received unique document ID and link to an API endpoint hosting the document:
{
"data": {
"type": "news.article",
"id": "59d80338ac610533b46bbc6b",
"attributes": {
"title": "What makes world go round"
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d80338ac610533b46bbc6b"
}
}
}
Document API endpoint will always be: /resources/<DOCUMENT_TYPE>/<DOCUMENT_ID>
.
API request to fetch document by ID is therefore:
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<DOCUMENT_ID>
Document fields¶
A document does not have to be returned will all fields. The client is able to instruct the system which document fields are returned and which to omit.
Example API request creating a document with a few attributes:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "news.article",
"attributes": {
"title": "What makes world go round",
"summary": "People make world go round",
"content": "Words can not express how long content this is...",
"rank": 4
}
}
}' \
-X POST https://api.jazer.io/resources/news.article
The response contains complete document will all fields:
{
"data": {
"type": "news.article",
"id": "59d806b9ac610533b46bbc71",
"attributes": {
"title": "What makes world go round",
"summary": "People make world go round",
"content": "Words can not express how long content this is...",
"rank": 4
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d806b9ac610533b46bbc71"
}
}
}
Query parameter fields supports document field customization. The syntax is: fields[<DOCUMENT_TYPE>]=<FIELD_NAMES>
, where FIELD_NAMES is a comma-separated list of field names.
Fetching news.article document with only fields title and rank can be accomplished using fields[news.article]=title,rank. Complete API request is:
curl --globoff -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<DOCUMENT_ID>?fields[news.article]=title,rank
The response will return only attributes title and rank. Fields type and id are always returned by the design. They cannot be omitted. Attributes summary and content are not returned. Since by the definition relationships are fields, the same would apply to them. Add to field names which relationships to return and the rest will be omitted.
{
"data": {
"type": "news.article",
"id": "59d806b9ac610533b46bbc71",
"attributes": {
"title": "What makes world go round",
"rank": 4
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d806b9ac610533b46bbc71"
}
}
}
Document inclusion¶
A document can specify related documents using relationships. The client is able to instruct the system to include related documents in the response. Query parameter include supports document inclusion. The syntax is: include=<RELATIONSHIP_PATHS>
, where RELATIONSHIP_PATHS is a comma-separated list of relationship paths.
Create writer document using API request:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "writer",
"attributes": {
"name": "John Smith"
}
}
}' \
-X POST https://api.jazer.io/resources/writer
Create two news.article documents linking previously created writer document using following API requests:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "news.article",
"attributes": {
"title": "John Smith Story Part 1"
},
"relationships": {
"author": {
"data": {
"type": "writer",
"id": "<JOHN_SMITH_WRITER_ID>"
}
}
}
}
}' \
-X POST https://api.jazer.io/resources/news.article
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "news.article",
"attributes": {
"title": "John Smith Story Part 2"
},
"relationships": {
"author": {
"data": {
"type": "writer",
"id": "<JOHN_SMITH_WRITER_ID>"
}
}
}
}
}' \
-X POST https://api.jazer.io/resources/news.article
Create another writer document using API request:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "writer",
"attributes": {
"name": "Jane Doe"
}
}
}' \
-X POST https://api.jazer.io/resources/writer
Create news.article document linking newly created writer and previously created news articles using API request:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "news.article",
"attributes": {
"title": "Thoughts On John Smith Stories"
},
"relationships": {
"author": {
"data": {
"type": "writer",
"id": "<JANE_DOE_WRITER_ID>"
}
},
"similar": {
"data": [
{
"type": "news.article",
"id": "<JOHN_SMITH_NEWS_ARTICLE_1_ID>"
},
{
"type": "news.article",
"id": "<JOHN_SMITH_NEWS_ARTICLE_2_ID>"
}
]
}
}
}
}' \
-X POST https://api.jazer.io/resources/news.article
To-one relationship inclusion¶
Document news.article has an author relationship which points to a writer document. Using query parameter include=author while fetching a news.article document will include a writer document based on the ID in the author relationship.
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<JOHN_SMITH_NEWS_ARTICLE_1_ID>?include=author
The response with a news.article document and an included writer document:
{
"data": {
"type": "news.article",
"id": "59d8c719ac610533b46bbc7e",
"attributes": {
"title": "John Smith Story Part 1"
},
"relationships": {
"author": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e/relationships/author",
"related": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e/author"
},
"data": {
"type": "writer",
"id": "59d8c570ac610533b46bbc7c"
}
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e"
}
},
"included": [
{
"type": "writer",
"id": "59d8c570ac610533b46bbc7c",
"attributes": {
"name": "John Smith"
},
"links": {
"self": "https://api.jazer.io/resources/writer/59d8c570ac610533b46bbc7c"
}
}
]
}
To-many relationship inclusion¶
Document news.article whose author is Jane Doe has a similar relationship which points to multiple news.article documents. They can be included in the response alongside primary news.article document using query parameter include=similar.
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<JANE_DOE_NEWS_ARTICLE_ID>?include=similar
The response contains a primary news.article document and an included news.article documents:
{
"data": {
"type": "news.article",
"id": "59d8c90bac610533b46bbc84",
"attributes": {
"title": "Thoughts On John Smith Stories"
},
"relationships": {
"author": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/relationships/author",
"related": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/author"
},
"data": {
"type": "writer",
"id": "59d8c7c8ac610533b46bbc82"
}
},
"similar": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/relationships/similar",
"related": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/similar"
},
"data": [
{
"type": "news.article",
"id": "59d8c719ac610533b46bbc7e"
},
{
"type": "news.article",
"id": "59d8c734ac610533b46bbc80"
}
]
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84"
}
},
"included": [
{
"type": "news.article",
"id": "59d8c719ac610533b46bbc7e",
"attributes": {
"title": "John Smith Story Part 1"
},
"relationships": {
"author": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e/relationships/author",
"related": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e/author"
},
"data": {
"type": "writer",
"id": "59d8c570ac610533b46bbc7c"
}
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e"
}
},
{
"type": "news.article",
"id": "59d8c734ac610533b46bbc80",
"attributes": {
"title": "John Smith Story Part 2"
},
"relationships": {
"author": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c734ac610533b46bbc80/relationships/author",
"related": "https://api.jazer.io/resources/news.article/59d8c734ac610533b46bbc80/author"
},
"data": {
"type": "writer",
"id": "59d8c570ac610533b46bbc7c"
}
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c734ac610533b46bbc80"
}
}
]
}
Deeply nested relationship inclusion¶
Document inclusion is not limited to relationships on the primary document, i.e. the first level of inclusion. Document news.article whose author is Jane Doe has a similar relationships which points to a multiple news.article documents. Document of type news.article has an author relationship. Authors of similar news article documents can be included using query parameter include=similar.author. The inclusion of both primary document author and similar document authors can be achieved with query parameter include=author,similar.author.
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<JANE_DOE_NEWS_ARTICLE_ID>?include=author,similar.author
The response contains primary news.article document with an included author of the primary document, similar news.article documents and authors of similar documents. Intermediate documents like similar news.article documents are included automatically to provide full linkage. There is no need to write query parameter like include=author,similar,similar.author, since similar relationship must be traversed in order to resolve its author.
{
"data": {
"type": "news.article",
"id": "59d8c90bac610533b46bbc84",
"attributes": {
"title": "Thoughts On John Smith Stories"
},
"relationships": {
"author": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/relationships/author",
"related": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/author"
},
"data": {
"type": "writer",
"id": "59d8c7c8ac610533b46bbc82"
}
},
"similar": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/relationships/similar",
"related": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84/similar"
},
"data": [
{
"type": "news.article",
"id": "59d8c719ac610533b46bbc7e"
},
{
"type": "news.article",
"id": "59d8c734ac610533b46bbc80"
}
]
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c90bac610533b46bbc84"
}
},
"included": [
{
"type": "news.article",
"id": "59d8c719ac610533b46bbc7e",
"attributes": {
"title": "John Smith Story Part 1"
},
"relationships": {
"author": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e/relationships/author",
"related": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e/author"
},
"data": {
"type": "writer",
"id": "59d8c570ac610533b46bbc7c"
}
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c719ac610533b46bbc7e"
}
},
{
"type": "news.article",
"id": "59d8c734ac610533b46bbc80",
"attributes": {
"title": "John Smith Story Part 2"
},
"relationships": {
"author": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c734ac610533b46bbc80/relationships/author",
"related": "https://api.jazer.io/resources/news.article/59d8c734ac610533b46bbc80/author"
},
"data": {
"type": "writer",
"id": "59d8c570ac610533b46bbc7c"
}
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d8c734ac610533b46bbc80"
}
},
{
"type": "writer",
"id": "59d8c7c8ac610533b46bbc82",
"attributes": {
"name": "Jane Doe"
},
"links": {
"self": "https://api.jazer.io/resources/writer/59d8c7c8ac610533b46bbc82"
}
},
{
"type": "writer",
"id": "59d8c570ac610533b46bbc7c",
"attributes": {
"name": "John Smith"
},
"links": {
"self": "https://api.jazer.io/resources/writer/59d8c570ac610533b46bbc7c"
}
}
]
}
Inclusion security¶
The system will not include a document for which client does not have permission to access. API key must have permission path which matches document endpoint with allowed GET method.
A document might have relationship with type writer and ID 59d8c570ac610533b46bbc7c. To support a document inclusion, API key must have permission with a path like /resources/writer/[0-9a-fA-F]{24} and allowed GET method. Basically, if the client can read the document by ID then it can be included.
Document relationships¶
A document relationship has a unique endpoint which can be used to directly read its value. The endpoint path is a document path appended with /relationships/<RELATIONSHIP_NAME>
. The endpoint provides only links to related documents. There is an additional relationship endpoint which provides related documents linked by relationship. Its endpoint is a document path appended with /<RELATIONSHIP_NAME>
.
Create two news.article documents where one links the other:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "news.article",
"attributes": {
"name": "New Beginnings"
}
}
}' \
-X POST https://api.jazer.io/resources/news.article
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "news.article",
"attributes": {
"name": "Past, Present, Future"
},
"relationships": {
"similar": {
"data": [
{
"type": "news.article",
"id": "<NEWS_ARTICLE_1_ID>"
}
]
}
}
}
}' \
-X POST https://api.jazer.io/resources/news.article
The response from later will have links in the relationships which can be used:
{
"data": {
"type": "news.article",
"id": "59d9031bac610533b46bbc9b",
"attributes": {
"name": "Past, Present, Future"
},
"relationships": {
"similar": {
"links": {
"self": "https://api.jazer.io/resources/news.article/59d9031bac610533b46bbc9b/relationships/similar",
"related": "https://api.jazer.io/resources/news.article/59d9031bac610533b46bbc9b/similar"
},
"data": [
{
"type": "news.article",
"id": "59d902ccac610533b46bbc99"
}
]
}
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d9031bac610533b46bbc9b"
}
}
}
Example API request fetches similar relationship value:
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_2_ID>/relationships/similar
The response contains requested relationship value:
{
"data": [
{
"type": "news.article",
"id": "59d902ccac610533b46bbc99"
}
]
}
To fetch similar relationship documents use following API request:
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_2_ID>/similar
The response contains related documents:
{
"data": [
{
"type": "news.article",
"id": "59d902ccac610533b46bbc99",
"attributes": {
"name": "Past, Present, Future"
},
"links": {
"self": "https://api.jazer.io/resources/news.article/59d902ccac610533b46bbc99"
}
}
]
}
Document ACL¶
Create a user using API request:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
"data": {
"type": "core.user",
"attributes": {
"username": "jane.doe",
"password": "weCanWorkItOut"
}
}
}' \
-X POST https://api.jazer.io/users/core.user
Create a user token for the user using API request:
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-H 'Authorization: Basic amFuZS5kb2U6d2VDYW5Xb3JrSXRPdXQ=' \
-X POST https://api.jazer.io/users/core.user.token
The response contains an authentication token:
{
"data": {
"type": "core.user.token",
"id": "59da640dac610533b46bbcab",
"attributes": {
"token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6eyJ0eXBlIjoiY29yZS51c2VyLnRva2VuIiwiaWQiOiI1OWRhNjQwZGFjNjEwNTMzYjQ2YmJjYWIifSwidXNlciI6eyJ0eXBlIjoiY29yZS51c2VyIiwiaWQiOiI1OWRhNjMxNmFjNjEwNTMzYjQ2YmJjYTUifSwiaXNzIjoiamF6ZXIiLCJpYXQiOjE1MDc0ODQ2ODUsImV4cCI6MTUxMDA3NjY4NX0.MEYCIQC-K4RKx3Onm_XXd247hpT0_G6pJTKZCQ7sNkLpONqq0AIhAJob9wliovN3QziMP4B98BH6mv8qVLT13GCf3rDl_Gob",
"created": "2017-10-08T17:44:45.392Z"
},
"relationships": {
"user": {
"data": {
"type": "core.user",
"id": "59da6316ac610533b46bbca5"
}
}
}
}
}
Create note document using Jane Doe token:
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-H 'Authorization: Token <JANE_DOE_USER_TOKEN>' \
-d '
{
"data": {
"type": "note",
"attributes": {
"name": "Take out the trash",
"completed": false
}
}
}' \
-X POST https://api.jazer.io/resources/note
ACL¶
Document ACL can be fetched using API endpoint /resources/<DOCUMENT_TYPE>.acl/<DOCUMENT_ID>
.
Example API request fetches created note document ACL:
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-H 'Authorization: Token <JANE_DOE_USER_TOKEN>' \
-X GET https://api.jazer.io/resources/note.acl/<CREATED_NOTE_ID>
The response contains a document ACL with read, update and delete lists. Jane Doe created the document, therefore has all the rights.
{
"data": {
"type": "note.acl",
"id": "59da65c2ac610533b46bbcaf",
"attributes": {
"read": [
{
"id": "59da6316ac610533b46bbca5",
"type": "core.user"
}
],
"update": [
{
"id": "59da6316ac610533b46bbca5",
"type": "core.user"
}
],
"delete": [
{
"id": "59da6316ac610533b46bbca5",
"type": "core.user"
}
]
},
"links": {
"self": "https://api.jazer.io/resources/note.acl/59da65c2ac610533b46bbcaf"
}
}
}
Super ACL¶
Document super ACL can be fetched using API endpoint /resources/<DOCUMENT_TYPE>.acl.acl/<DOCUMENT_ID>
.
Example API request fetches created note document super ACL:
curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-H 'Authorization: Token <JANE_DOE_USER_TOKEN>' \
-X GET https://api.jazer.io/resources/note.acl.acl/<CREATED_NOTE_ID>
The response will contain a document ACL with read and update lists. Jane Doe created the document, therefore has both rights.
{
"data": {
"type": "note.acl.acl",
"id": "59da65c2ac610533b46bbcaf",
"attributes": {
"read": [
{
"id": "59da6316ac610533b46bbca5",
"type": "core.user"
}
],
"update": [
{
"id": "59da6316ac610533b46bbca5",
"type": "core.user"
}
]
},
"links": {
"self": "https://api.jazer.io/resources/note.acl.acl/59da65c2ac610533b46bbcaf"
}
}
}
Conditional get¶
Successful read API request will return a response with the ETag header. Repeating the same request with an additional header If-None-Match with the value of an ETag value from previous response can have two outcomes. The server can return 200 OK with the body if the primary document or any of the included documents have changed or 304 Not Modified without a body when there have been no changes to the documents since last request, i.e. the given ETag is still valid.
Example API request fetches document of type news.article:
curl -i -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_ID>
The response will be 200 OK with the body containing news.article document. Response headers will contain an ETag. Repeating the same API request with an additional header If-None-Match with the value of ETag returned from this response like:
curl -i -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-H 'If-None-Match: <ETAG_VALUE>' \
-X GET https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_ID>
The response will be 304 Not Modified if in the meantime news.article document with the given ID has not been modified or removed.
Note
Web browsers support such local caching automatically.