Collections

Collections and documents are analogous to directories and files (respectively) on a file system.

Defining collections for listing and reading documents

A collection is defined and named in the blueprint. Collection names are case-sensitive, and both upper- and lower-case names are valid.

Collections have two components that need to be specified. They are the collection endpoint and the corresponding document endpoint for that collection. When listing documents from a collection endpoint, the corresponding document endpoint’s Access Control List is used to determine if a document shows in the list. The collection endpoint Access Control List determines if the request will return a 200 response code in the case of access granted or a 403 Forbidden response code when access is not granted.

At both endpoints, defining an access control list is required with the x-datastore-acl tag. This is still required, even if it is to assert that access is open to the public.

Using an API specification file (based on OpenAPI v3) written in YAML format and JSON schema data model files, you can create a collection listing documents representing events and individually viewing events from a document endpoint. Access will be public. We will assign eventid as the unique documentid for events.

The way documents are listed is defined in a collection list JSON schema file ./schemas/events.json JSON schema file. This should define the array of documents and what properties each document has by referring to another JSON schema file.

For example:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "array",
    "items": {
        "$ref": "./event.json"
    }
}

The same or a different JSON schema file can be set for the document endpoint.

This is how a developer can control what document properties show when listing documents of a collection and what document properties show when viewing a document.

/events:
  get:
    x-datastore-acl: public
    responses:
      "200":
        description: OK
        content:
          application/json:
            schema:
              $ref: "./schemas/events.json"

/events/{eventid}:
  parameters:
    - in: path
      name: eventid
      required: true
      schema:
        type: string
  get:
    x-datastore-acl: public
    responses:
      "200":
        description: OK
        content:
          application/json:
            schema:
              $ref: "./schemas/event.json"

Get documents in a collection

You get documents into a collection by making a GET request to the collections endpoint.

This example uses CURL:

curl \
    -X GET \
    -H "Content-Type: application/json" \
    --silent \
    -fS https://my-data-service.datastore.squiz.cloud/events

Alternatively, Squiz Data Services provides a JavaScript SDK that lets you add documents to a collection: [features:javascript-sdk]

Define collections for creating and updating documents

You must implement POST and patch API methods to enable documents to be created and updated. A POST method on the collection endpoint will enable the creation of documents where a UUID (Universal Unique Identifier) will be assigned as the document ID. The patch method on the document endpoint will allow the properties to be updated for existing documents.

A requestBody and responses tag must be defined in both API methods. Again, you need to define the JSON schema for all methods. The requestBody JSON schema defines what properties are accepted on create/update. The response JSON schema defines the properties in the response to these requests. These JSON schema files can differ from one another when you want to vary the properties used in each request.

We have expanded our events example below by adding post and patch endpoints:

/events:
  get:
    ...
  post:
    x-datastore-acl: public
    responses:
      "201":
        description: Created
        content:
          application/json:
            schema:
              $ref: "./schemas/event.json"
    requestBody:
      content:
        application/json:
          schema:
            $ref: "./schemas/event.json"
/events/{eventid}:
  parameters:
    - in: path
      name: eventid
      required: true
      schema:
        type: string
  get:
    ...
  patch:
    x-datastore-acl: public
    responses:
      "200":
        description: OK
        content:
          application/json:
            schema:
              $ref: "./schemas/event.json"
    requestBody:
      content:
        application/json:
          schema:
            $ref: "./schemas/event.json"

Add a document to a collection

Adding documents to a collection is done by making a POST request to the collections endpoint. This example uses CURL:

curl \
    -X POST \
    -H "Content-Type: application/json" \
    --silent \
    -d "$documentData" \
    -fS https://my-data-service.datastore.squiz.cloud/events

Alternatively, Squiz Data Services provides a JavaScript SDK that aids in creating documents: [features:javascript-sdk]

Define collections for setting documents

The PUT API method allows a collection to create a document with a defined document ID, or if the document with that same ID already exists, it will overwrite the entire document with the property values in the request.

The PUT method can only be defined on the document endpoint.

We have expanded our events example below by adding a PUT method below -

/events:
  get:
    ...
  post:
    ...
/events/{eventid}:
  parameters:
    - in: path
      name: eventid
      required: true
      schema:
        type: string
  get:
    ...
  patch:
    ...
  put:
    x-datastore-acl: public
    responses:
      "201":
        description: Created
        content:
          application/json:
            schema:
              $ref: "./schemas/event.json"
    requestBody:
      content:
        application/json:
          schema:
            $ref: "./schemas/event.json"

Define collections for deleting documents

The DELETE API method allows a collection to delete an existing document with a matching document ID.

The DELETE method can only be defined on the document endpoint.

We have expanded our events example below by adding a DELETE method below -

/events:
  get:
    ...
  post:
    ...
/events/{eventid}:
  parameters:
    - in: path
      name: eventid
      required: true
      schema:
        type: string
  get:
    ...
  patch:
    ...
  put:
    ...
  delete:
    x-datastore-acl: public
    responses:
      "204":
        description: No Content

Define collection aliases

Collections can be aliased to one another using the collection alias feature. This allows multiple collection paths to reference the same collection of documents, with the ability to have different document properties specified for the alias.

The documents will comprise all the properties defined for the primary collection as all the collection aliases.

Collection aliases can have differing methods and Access Control Lists as well. A typical pattern is having a public collection and defining an administrative collection that shows more properties and is only accessible to administrators defined by a JWT-defined value and enforced by an ACL rule.

In our example we will have the main events endpoints for public use. We will enable only listing and viewing of events.

In the administrative collection alias, we will define extra methods, show different properties, and enforce different access controls while managing the same documents.

/events:
  get:
    ...
/events/{eventid}:
  parameters:
    - in: path
      name: eventid
      required: true
      schema:
        type: string
  get:
    ...

/events-admin:
  x-datastore-collection-alias: /events
  get:
    x-datastore-acl: JWT.isAdmin === true
    responses:
      "200":
        description: OK
        content:
          application/json:
            schema:
              $ref: "./schemas/admin-events.json"

  post:
    x-datastore-acl: JWT.isAdmin === true
    responses:
      "201":
        description: Created
        content:
          application/json:
            schema:
              $ref: "./schemas/admin-event.json"
    requestBody:
      content:
        application/json:
          schema:
            $ref: "./schemas/admin-event.json"

/events-admin/{eventid}:
  parameters:
    - in: path
      name: eventid
      required: true
      schema:
        type: string
  get:
    x-datastore-acl: JWT.isAdmin === true
    responses:
      "200":
        description: OK
        content:
          application/json:
            schema:
              $ref: "./schemas/admin-event.json"

  patch:
    x-datastore-acl: JWT.isAdmin === true
    responses:
      "200":
        description: OK
        content:
          application/json:
            schema:
              $ref: "./schemas/admin-event.json"
    requestBody:
      content:
        application/json:
          schema:
            $ref: "./schemas/admin-event.json"
  put:
    x-datastore-acl: JWT.isAdmin === true
    responses:
      "201":
        description: Created
        content:
          application/json:
            schema:
              $ref: "./schemas/admin-event.json"
    requestBody:
      content:
        application/json:
          schema:
            $ref: "./schemas/admin-event.json"
  delete:
    x-datastore-acl: JWT.isAdmin === true
    responses:
      "204":
        description: No Content

Response codes

Collection requests return the following HTTP response code:

HTTP Method HTTP code Notes

GET

200 OK

Returned when the document or collection exists.

POST

201 Created

Returned when posting to a collection to create a document inside that collection.

Code Description JSON

400 Bad Request

Returned when a POST, PATCH, or PUT request contains invalid or missing property data. A 400 Bad Request error object contains an additional property called invalid-params, which lists the validation error for each invalid or missing document property. Each property validation error is an object containing a name and reason property. The name is the name of the document property that was invalid or missing. The reason is a user-friendly error message describing the validation error.

{
   "title": "JSON does not validate.",
   "status ": "400",
   "invalid-params": [
      {
           "name": "comment",
           "reason": "Comment length must not exceed 5000 characters"
      }
   ]
}

401 Unauthorized

Returned when an ACL protects a request, but no valid JWT was provided with the request. This can be caused by no JWT being sent or the supplied JWT not being signed with the correct secret key and cannot be decoded. Squiz Data Services returns 401 Unauthorized instead of 403 Forbidden to indicate no user data against which to compare. So, it is unknown if the current user is allowed to make the request.

{
   "title": "Unauthorized",
   "status": "401"
}

403 Forbidden

Returned when an ACL rule failed for a request. No additional information about what rule failed is supplied in the error object to avoid information leakage.

{
   "title": "Forbidden",
   "status": "403"
}

404 Not found

Returned when the requested document or collection does not exist. The title of the error message indicates the requested resource type.

{
   "title": "Document not found",
   "status": "404"
}

{
   "title": "Collection not found",
   "status": "404"
}

405 Method Not Allowed

Returned when the HTTP method has not been defined inside the API description document for the requested path.

{
   "title": "Method Not Allowed",
   "status": "405"
}