Delivery API

Errors

What each error looks like and how to fix it.

Errors come in two kinds. Problems with the HTTP request, like a missing key or too many requests, get a 4xx status. Problems with the query itself get a 200 or 400 with a GraphQL errors array. Check both.

HTTP errors#

StatusBodyWhat to do
400BAD_REQUESTThe body isn’t valid JSON. Send JSON with a query field, and the Content-Type: application/json header.
400UNAUTHENTICATEDThe key has expired. Create a new one in the project’s API page.
401{"error":"Unauthorized: Bearer token missing or malformed"}Send the key as Authorization: Bearer <key>.
401{"error":"Unauthorized."}The key doesn’t exist or was revoked. Check it for typos, or create a new one.
413EmptyThe body is larger than 256 KB. Send a shorter query, and use variables instead of inlining values.
429Rate limit exceeded.More than 25 requests in a second from your IP address. Wait a second and retry, and cache responses.

Authentication and rate limits explain these in more detail.

GraphQL errors#

When the query can’t run, the response has status 200, no data and an errors array. Each error has a readable message, where it is in the query and a code:

Response
{
"errors": [
{
"message": "Cannot query field \"titel\" on type \"Document\". Did you mean \"title\"?",
"locations": [{ "line": 1, "column": 32 }],
"extensions": { "code": "GRAPHQL_VALIDATION_FAILED" }
}
]
}
CodeCauseWhat to do
BAD_REQUESTThe body has no query.Send the query in the query field of the JSON body.
GRAPHQL_PARSE_FAILEDThe query has a syntax error, like a missing brace.Fix the syntax at the location in the error.
GRAPHQL_VALIDATION_FAILEDThe query asks for a field or argument that doesn’t exist, is missing a required variable, or is too complex.Check names against the types, pass every variable, and lower limit or drop html from lists.

Not found isn’t an error#

document and documentBySlug return null when there’s no published document with that id or slug, and documentsInCategory returns an empty list for an unknown category. There’s no error, so check for null and show your 404 page.

Handle errors#

A small wrapper that turns every kind of error into an exception with a message you can log:

pmkin.js
async function queryPmkin(query, variables) {
const response = await fetch('https://content.pmkin.io/graphql', {
body: JSON.stringify({ query, variables }),
headers: {
Authorization: `Bearer ${process.env.PMKIN_API_KEY}`,
'Content-Type': 'application/json'
},
method: 'POST',
signal: AbortSignal.timeout(10_000)
})
// 401, 413 and 429 don't have a GraphQL body.
if (response.status === 429) {
throw new Error('PMKIN rate limit reached. Retry in a second.')
}
if (response.status === 401) {
throw new Error('PMKIN rejected the delivery key. Check PMKIN_API_KEY.')
}
const body = await response.json().catch(() => {
return null
})
if (body?.errors) {
throw new Error(`PMKIN: ${body.errors[0].message}`)
}
if (!response.ok || !body) {
throw new Error(`PMKIN returned ${response.status}`)
}
return body.data
}
// Not found isn't an error: show your 404 page when this returns null.
async function loadDocument(slug) {
const data = await queryPmkin(
'query ($slug: String!) { documentBySlug(slug: $slug) { title html } }',
{ slug }
)
return data.documentBySlug
}