Update

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, PATCH off
/resources/news\.article/[0-9a-fA-F]{24}/relationships/reviewers GET, POST, DELETE off
/resources/writer POST off
/users/core\.user POST off
/users/core\.user\.token POST off
/resources/message POST on
/resources/message\.acl/[0-9a-fA-F]{24} GET, PATCH on
/resources/message\.acl\.acl/[0-9a-fA-F]{24} GET, PATCH on

Document

Create news.article document with an 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": "Hello World",
      "summary": ""
    }
  }
}' \
-X POST https://api.jazer.io/resources/news.article

The created document contains attributes title and summary. Update operation can change existing fields and/or add new ones. Example API request changes attribute summary and adds new attribute rank:

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",
    "id": "59da8d86ac610533b46bbcbb",
    "attributes": {
      "summary": "See the world",
      "rank": 5
    }
  }
}' \
-X PATCH https://api.jazer.io/resources/news.article/<DOCUMENT_ID>

Patch document does not contain title attribute. This does not mean title attribute should be removed, i.e. it means it should remain the same. All existing fields will remain the same. Fetching complete document can verify the statement:

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>

The response contains a title attribute with the initial value, summary with the updated value and rank:

{
  "data": {
    "type": "news.article",
    "id": "59da8d86ac610533b46bbcbb",
    "attributes": {
      "title": "Hello World",
      "summary": "See the world",
      "rank": 5
    },
    "links": {
      "self": "https://api.jazer.io/resources/news.article/59da8d86ac610533b46bbcbb"
    }
  }
}

Document relationships

Document relationship has a unique endpoint which can be used to directly update its value. Endpoint path is document path appended with /relationships/<RELATIONSHIP_NAME>.

Create two writer documents using 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": "writer",
    "attributes": {
      "name": "Kenny McCormick"
    }
  }
}' \
-X POST https://api.jazer.io/resources/writer
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": "Stan Marsh"
    }
  }
}' \
-X POST https://api.jazer.io/resources/writer

Replace

Create news.article document linking first writer with an 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",
    "relationships": {
      "author": {
        "data": {
          "type": "writer",
          "id": "<KENNY_MCCORMICK_WRITER_ID>"
        }
      }
    }
  }
}' \
-X POST https://api.jazer.io/resources/news.article

Relationship value can be replaced using PATCH method on the relationship endpoint. Example API request replaces news.article document author relationship:

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",
    "id": "<STAN_MARSH_WRITER_ID>"
  }
}' \
-X PATCH https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_ID>/relationships/author

Relationship value can be verified with an 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_ID>/relationships/author

Append

Create news.article document with to-many relationship initially linking only one writer with an 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",
    "relationships": {
      "reviewers": {
        "data": [
          {
            "type": "writer",
            "id": "<KENNY_MCCORMICK_WRITER_ID>"
          }
        ]
      }
    }
  }
}' \
-X POST https://api.jazer.io/resources/news.article

Add another writer link to reviewers relationship using an 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",
    "id": "<STAN_MARSH_WRITER_ID>"
  }]
}' \
-X POST https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_ID>/relationships/reviewers

Relationship value can be verified with an 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_ID>/relationships/reviewers

Append operation can add one or many links to a relationship. Performing append operation onto to-one relationship will automatically convert relationship into a to-many relationship.

Remove

Create news.article document with to-many relationship initially linking two writers with an 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",
    "relationships": {
      "reviewers": {
        "data": [
          {
            "type": "writer",
            "id": "<KENNY_MCCORMICK_WRITER_ID>"
          },
          {
            "type": "writer",
            "id": "<STAN_MARSH_WRITER_ID>"
          }
        ]
      }
    }
  }
}' \
-X POST https://api.jazer.io/resources/news.article

Remove second writer link from reviewers relationship using an 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",
    "id": "<STAN_MARSH_WRITER_ID>"
  }]
}' \
-X DELETE https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_ID>/relationships/reviewers

Relationship value can be verified with an 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_ID>/relationships/reviewers

Remove operation can remove one or many links from a relationship. Performing remove operation onto to-one relationship will automatically convert relationship into a to-many relationship.

Document ACL

Create a user using an 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": "joe.blow",
      "password": "otherBlowIsNaysayer88"
    }
  }
}' \
-X POST https://api.jazer.io/users/core.user

Create a user token for the user using an 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 am9lLmJsb3c6b3RoZXJCbG93SXNOYXlzYXllcjg4' \
-X POST https://api.jazer.io/users/core.user.token

The response contains an authentication token:

{
  "data": {
    "type": "core.user.token",
    "id": "59dbf8a7ac610520d073cb84",
    "attributes": {
      "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6eyJ0eXBlIjoiY29yZS51c2VyLnRva2VuIiwiaWQiOiI1OWRiZjhhN2FjNjEwNTIwZDA3M2NiODQifSwidXNlciI6eyJ0eXBlIjoiY29yZS51c2VyIiwiaWQiOiI1OWRiZjg1NmFjNjEwNTIwZDA3M2NiODAifSwiaXNzIjoiamF6ZXIiLCJpYXQiOjE1MDc1ODgyNjMsImV4cCI6MTUxMDE4MDI2M30.MEUCIQCRmP0KgachGssV9zjfKZjXB-69uXyqKP20I-VGDvqCBgIgeT9U75GTJbwZ44cm8V1H92MnJtb4zOmXuyWR08F_nqo",
      "created": "2017-10-09T22:31:03.918Z"
    },
    "relationships": {
      "user": {
        "data": {
          "type": "core.user",
          "id": "59dbf856ac610520d073cb80"
        }
      }
    }
  }
}

Create a message document using Joe Blow 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 <JOE_BLOW_USER_TOKEN>' \
-d '
{
  "data": {
    "type": "message",
    "attributes": {
      "title": "New product demo is today!"
    }
  }
}' \
-X POST https://api.jazer.io/resources/message

Create another user using an 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": "gabriel.glass",
      "password": "fluffyPower"
    }
  }
}' \
-X POST https://api.jazer.io/users/core.user

ACL

Document ACL can be updated using API endpoint /resources/<DOCUMENT_TYPE>.acl/<DOCUMENT_ID>.

Joe Blow has all rights on created message since he created the document. Example API request allows the read operation to all users and the update operation to the user Gabriel Glass.

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 <JOE_BLOW_USER_TOKEN>' \
-d '
{
  "data": {
    "type": "message.acl",
    "id": "<MESSAGE_ID>",
    "attributes": {
      "read": "*",
      "update": [
        {
          "type": "core.user",
          "id": "<JOE_BLOW_USER_ID>"
        },
        {
          "type": "core.user",
          "id": "<GABRIEL_GLASS_USER_ID>"
        }
      ]
    }
  }
}' \
-X PATCH https://api.jazer.io/resources/message.acl/<MESSAGE_ID>

Verify message document ACL using an 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: Token <JOE_BLOW_USER_TOKEN>' \
-X GET https://api.jazer.io/resources/message.acl/<MESSAGE_ID>

The response contains modified read and update lists:

{
  "data": {
    "type": "message.acl",
    "id": "59dbf9e4ac610520d073cb88",
    "attributes": {
      "read": "*",
      "update": [
        {
          "type": "core.user",
          "id": "59dbf856ac610520d073cb80"
        },
        {
          "type": "core.user",
          "id": "59dbfb89ac610520d073cb8a"
        }
      ],
      "delete": [
        {
          "type": "core.user",
          "id": "59dbf856ac610520d073cb80"
        }
      ]
    },
    "links": {
      "self": "https://api.jazer.io/resources/message.acl/59dbf9e4ac610520d073cb88"
    }
  }
}

Super ACL

Document super ACL can be updated using API endpoint /resources/<DOCUMENT_TYPE>.acl.acl/<DOCUMENT_ID>.

Joe Blow has all the rights on a created message since he created the document. Example API request allows read and update operation to the user Gabriel Glass.

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 <JOE_BLOW_USER_TOKEN>' \
-d '
{
    "data": {
      "type": "message.acl.acl",
      "id": "<MESSAGE_ID>",
      "attributes": {
        "read": [
          {
            "type": "core.user",
            "id": "<JOE_BLOW_USER_ID>"
          },
          {
            "type": "core.user",
            "id": "GABRIEL_GLASS_USER_ID"
          }
        ],
        "update": [
          {
            "type": "core.user",
            "id": "<JOE_BLOW_USER_ID>"
          },
          {
            "type": "core.user",
            "id": "GABRIEL_GLASS_USER_ID"
          }
        ]
      }
    }
  }
' \
-X PATCH https://api.jazer.io/resources/message.acl.acl/<MESSAGE_ID>

Gabriel Glass can now change message document ACL. He can allow/deny rights to any user for this message document.

Concurrency control

Problems like the lost update problem where two or more clients fetch the same version of a document and then at the same time request document update, causes one update to overwrite the other. To solve concurrent update problems, the system supports HTTP conditional requests with If-Match header. When client inserts or fetches document (via a read or search endpoint) response will contain an ETag header. Returned ETag can be used for any document returned in the response (both primary and included). The client simply needs to make an API request with the header If-Match containing an ETag value. The server will return status code 204 No Content when update succeeds. Otherwise, if the document has been modified in the meantime, the server will return 412 Precondition Failed. This means supplied ETag is no longer valid for the document and the client needs to perform fetch request to get updated document and use newly issued ETag from the latter API response.

Example search API request:

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?include=author

Response body can contain documents of type news.article (as primary) and writer (as included via author relationship). Response headers contain an ETag. As stated before, ETag can be used for any document in the response.

Example API request updates news.article document supplying If-Match header:

curl -i -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 'If-Match: <ETAG_VALUE>' \
-d '
{
  "data": {
    "type": "news.article",
    "id": "<NEWS_ARTICLE_ID>",
    "attributes": {
      "summary": "It was a beautiful day"
    }
  }
}' \
-X PATCH https://api.jazer.io/resources/news.article/<NEWS_ARTICLE_ID>

When example API request is performed twice in a row with the same news article ID and the same ETag, the first API request will return 204 No Content, while the second will return 412 Precondition Failed.