Scrivito as a Headless CMS: The RESTful API

A brief introduction to headless CMSs

Scrivito includes a RESTful API for retrieving content from within any application able to issue web requests, e.g. mobile applications. This fully qualifies Scrivito as a headless CMS even though it comes with a WYSIWYG editing interface.

A headless CMS provides an API for accessing the content stored in a repository. It does not provide the means to present this content, i.e. to visualize it and make it accessible to the audience. This makes a headless CMS an ideal solution in situations where, due to special requirements or the diversity of the platforms to address, standard presentation technology cannot be applied and thus tailored interfaces (heads) are needed. 

With a headless CMS, having a flexible content maintenance tool as one of its heads is essential. If the same content is to be used on platforms that are different with respect to their capabilities, operability, etc., special fields or attributes may be required to control where which pieces of content should be used in which way.

With Scrivito, such requirements can be met easily due to customizable object classes (content models), its standard output format (JSON), and an easy-to-use in-place editing interface for maintaining all aspects of the content. All you would need is a minimalistic custom web application for browsing the content.

Scrivito’s RESTful API

Scrivito’s RESTful API gives you read access to CMS objects and binary data and lets you perform searches. All access is restricted to the published content, meaning that working copies cannot be addressed.

To issue an API request, you require the ID of the CMS tenant to query, represented as the tenant_id part in the URL templates below. For querying CMS objects or binaries, you require their ID which is represented as obj_id or, respectively, blob_id in the URL. For the published content of a CMS tenant to be accessible through REST API calls, at least one CORS origin must have been set for the tenant. You can specify the CORS origins of any of your CMS tenants via its “Settings” tab in your account.

The data returned by API calls is in JSON format. For brevity, the formatting of the example output given here may not be exactly equal to the formatting of the returned data. 

Fetching CMS objects


Request

Copy
curl https://api.scrivito.com/tenants/tenant_id/workspaces/published/objs/obj_id

Response

Copy
{
  "conflicts": null,
  "_created_at": "20170704154214",
  "_id": "0028b1560997eb97",
  "_modification": nil,
  "_path": nil,
  "_permalink": nil,
  "_last_changed": "20170704154214",
  "_version": "201707061451190000000000000000531bec4294dc8ce5",
  "_widget_pool": {
    "00000001": {
      "_obj_class": "TextWidget",
      "text": [
        "html",
        "Lorem Ipsum"
      ]
    },
    "00000002": {
      "_obj_class": "BoxWidget",
      "box_widgets": [
        "widgetlist",
        [ "00000003" ]
      ]
    },
    "00000003": {
      "_obj_class": "TextWidget",
      "text": [
        "html",
        "Contained in 00000002"
      ]
    }
  },
  "_obj_class": "Page",
  "_created_by": "e8c8f7837da9c25fbac8601f8dda025f",
  "_last_changed_by": "e8c8f7837da9c25fbac8601f8dda025f",
  "title": [
    "string",
    "Page Title"
  ],
  "main_content": [
    "widgetlist",
    [ "00000001", "00000002" ]
  ]
}

With binary objects, their blob would show up as:

Copy
{
  "_obj_class": "Image",
  "blob": [
    "binary",
    {"id": "00f8b1560c97eb94/4a7d12c1fde1/some-image.jpg"}
  ],
}

Remarks

  • Attributes are returned in the format "attr_name": attr_value. The name of internal attributes starts with an underscore. 
  • In JavaScript, attribute names are in camelcase, e.g. fontColor would be stored and returned as font_color.
  • The _widget_pool attribute contains all the widgets used on a page. Attributes of the widgetlist type (e.g. main_content in the example above) reference widgets in the _widget_pool.
  • The values of attributes referring to a user (e.g. _created_by) depend on the user management system used.

Fetching binary data

To retrieve the binary data from an attribute such as blob, the actual URL of the binary needs to be determined first. For this, extract the blob’s id and use it for querying the URL, like so:

Request

Copy
curl -X GET https://api.scrivito.com/tenants/tenant_id/workspaces/published/blobs/blob_id/optimize \
  -H 'Content-Type: application/json'

Response

Copy
{
  "public_access": {
    "get": {
      "url": "https://cdn0.scrvt.com/scrival/00f8b1560c97eb94/4a7d12c1fde1/some-image.jpg",
      "maxage": 604800
    },
    "head": {
      "url": "https://cdn0.scrvt.com/scrival/00f8b1560c97eb94/4a7d12c1fde1/some-image.jpg",
      "maxage": 604800
    }
  }
}

Using the url from the get dictionary inside public_access, you can now directly request the binary data.

Remarks

  • The file name part of the id of a blob may include escaped characters. After unescaping, apply URL encoding.

Searching

Request

Find CMS objects whose title or description attribute value starts with term:

Copy
curl https://api.scrivito.com/tenants/tenant_id/workspaces/published/objs/search \
  -X GET \
  -H 'Content-Type: application/json' \
  -d '{
    "query": [
      { "field": ["title", "description"],
      "operator": "contains_prefix",
      "value": "term" }
    ]
  }'

Same as above, but only find CMS objects not in the /products path (whose _path attribute value does not start with /products):

Copy
curl -X GET https://api.scrivito.com/tenants/tenant_id/workspaces/published/objs/search \
  -H 'Content-Type: application/json' \
  -d '{
    "query": [
      { "field": ["title", "description"],
      "operator": "contains_prefix",
      "value": "term" },
      { "field": "_path",
      "operator": "starts_with",
      "value": "/products",
      "negate": true }
    ]
  }'

Response

Copy
{
  "total": 109,
  "results": [
    {"id": "0028b1560997eb97"},
    {"id": "0036cdd0d32969d2"},
    {"id": "00eff53b042422ea"},
    {"id": "0137a38b837bd47d"},
    {"id": "01d4110c101e0490"},
    {"id": "02c04916ee8157d2"},
    {"id": "02dc4285745e08e7"},
    {"id": "03348c34aa95843d"},
    {"id": "034617d259ad31af"},
    {"id": "03727495ecbcdb6d"}
  ],
  "continuation": "[1,10,0]"
}

Remarks

  • The query component is an array. Additional array elements represent extensions to the query and restrict it using "and". To negate an additional query, specify the negate: true parameter like shown above.
  • The search results are returned as an array of dictionaries with a single value, the id of the respective CMS object.
  • The results list is incomplete if a response includes a continuation value. In this case, add the continuation key and value to the next request to fetch the next batch.
  • The value of field may be * which acts as a wildcard to have all attributes searched.
  • For the list of searchable attributes and the available operators, see the ObjSearch documentation.