Guide 06 · Developer docs

The APIs: REST, GraphQL and custom endpoints

Every Core dna site answers three kinds of API request under /cdna-api: REST for everything, GraphQL for reads that span several entity types, and web events for endpoints you define yourself as jobs. Which fits which task, one worked request for each, and what is true of all three. Jobs were called hooks until the module was renamed Orchestration; the API's routes still use the old name.

L1–L3
Unit 01 · The REST API

Query string or request body

Where each part of a request goes: filters and paging in the query string, the record in the body, and properties in either, depending on the method. The long selector that does not fit in a URL, and the one client that cannot send it.

Who this is for. The headless developer whose selectors have grown long, and anyone writing records. The rule is short:

MethodQuery stringBody
GETFilters, limit, page or offset, orderBy, and propertiesNothing, or only the properties selector (below)
POST, PUTproperties, to shape the answerThe record: JSON, or a form body when files are attached
DELETENothingNothing for one record; ids on the routes that delete in bulk

A write never reads properties from its body: the body is the record, and a field called properties would be taken as part of it.

A selector in the body of a GET

A selector that reaches through several relations soon outgrows a URL, and a proxy or CDN in front of the site can refuse the request before it arrives. So a GET may carry the selector in its body instead, with the header X-Body-Has-Parameters: 1. Two rules:

  • Only the selector is read from the body. Filters, limit and orderBy stay in the query string.
  • Send it raw, wrapped in its outer braces, exactly as it would appear after properties=. Any content type works.
A selector sent in the body of a GET
GET /cdna-api/pages/pages?parent.id=72 HTTP/1.1
Host: hub.coredna.com
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json
Content-Type: text/plain
X-Body-Has-Parameters: 1

{id,name,lede:activeRevision.areaText(lede)}
Response 200 OK
{
  "result": "success",
  "totalCount": 2,
  "data": [
    {
      "id": 818,
      "name": "API Reference",
      "lede": "Every endpoint of the Core dna REST API, with requests to copy in five languages and the real responses they return."
    },
    {
      "id": 1878,
      "name": "Reference",
      "lede": null
    }
  ]
}
Real response from this documentation site

Browsers cannot send it

A browser will not put a body on a GET: fetch throws a TypeError before the request leaves, and XMLHttpRequest drops the body silently. A script on the site's own pages therefore keeps its selectors short enough for the query string, or asks for less and makes two requests. Server-side clients such as cURL, Guzzle and Python's requests send the body without trouble. Node's built-in fetch refuses it as a browser does, so use a lower-level HTTP client there. Long selectors usually live on a server anyway: a headless front end calls the API from its server.

If a selector is long because a page needs content from several entity types, consider GraphQL, which takes its query in a POST body and fetches them in one round trip.

Bodies for writes

Send JSON with Content-Type: application/json unless a file is attached; then send a multipart form. Two things to check in a client:

  • A body that is not valid JSON is read as empty, and the edit answers 200, “The Page has been saved successfully.”. Serialise the body with a JSON library, and read the saved record back when it matters.
  • Put the selector in the query string to choose what the write returns: PUT /cdna-api/pages/page/72?properties={id,name,modified}.

What a write body may contain, field by field, is on each endpoint's reference page; how a write to versioned content behaves is in Writing content.

Go deeper

Was this page helpful?

Your answer goes to the docs team.