Справочник

GraphQL API

Същото публикувано съдържание като в REST API, през един адрес и със схема, изградена от вашите колекции. Връзките се зареждат в същата заявка.

Адрес#

POST/graphql

Изпълнява заявка с JSON тяло { query, variables, operationName, extensions }.

GET/graphql

Същото, но полетата са параметри в адреса (variables и extensions са кодирани като JSON). Удобно зад CDN.

Адресът е без /v1: https://api.console.citronos.com/graphql. Приема същите ключове като REST (ck_pub_ за публикуваното съдържание, ck_prev_ за черновите) в Authorization: Bearer … или x-api-key и дели с тях ограничението на заявките за всеки ключ.

GraphQL е модул, който се включва за работното пространство, и е част от плановете от Professional нагоре. Докато е изключен, /graphql отговаря с 404 на ключовете на това работно пространство.

curl https://api.console.citronos.com/graphql \
  -H "Authorization: Bearer $CITRON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"query ($n: Int) { products(pageSize: $n, locale: \"en\") { data { slug name } meta { total } } }","variables":{"n":10}}'

Вашата схема#

Всяко работно пространство има собствена схема, която се изгражда наново при промяна на колекция. Интроспекцията работи с всеки валиден ключ, така че GraphiQL, инструментите на Apollo или graphql-codegen могат да я прочетат. Имената идват от slug на колекциите:

Slug на колекциятаТипПоле за списъкПоле за един запис
productsProductproducts(…): ProductList!product(id, slug, …): Product
other-productsOtherProductotherProductsotherProduct
galleryGallerygalleryListgallery
site-settings (единична)SiteSettingнямаsiteSetting(…): SiteSetting
  • Всеки тип запис има id, slug, publishedAt, updatedAt и sortOrder, а след тях по едно поле за всяко поле на колекцията.
  • Полето за списък връща { data: [Entry!]!, meta: PageMeta! }, като meta съдържа total, page, pageSize и pageCount.
  • Полетата за изображения и медия са обекти Asset (url, width, height, alt, variants, focal), връзките са типът на свързания запис, а форматираният текст е String с аргумент format: HTML | JSON (JSON идва като низ).
  • Полето за един запис връща null, когато записът не съществува, вместо грешка.
  • Живите (външни) колекции не са в схемата. Няма мутации и абонаменти.

Филтри, сортиране и страници#

Полетата за списък приемат filter, sort, page, pageSize (най-много 100), locale и status. Филтрите следват REST: StringFilter и FloatFilter имат eq ne lt lte gt gte in notIn (низовете добавят contains), BooleanFilter има eq ne, а полетата със списъци приемат ListFilter { contains }. Най-много 10 условия. sort е едно { field, direction }.

GraphQL
query Stations($n: Int, $locale: String) {
  products(
    filter: { category: { eq: "station" }, capacity: { gte: 5 } }
    sort: { field: publishedAt, direction: DESC }
    page: 1
    pageSize: $n
    locale: $locale
  ) {
    data {
      id
      slug
      code
      name
      body(format: HTML)
      cover { url width height alt focal { x y } }
      specRows { label value }
      related { slug name }
    }
    meta { total page pageSize pageCount }
  }
}
GraphQL
query Product($slug: String!) {
  product(slug: $slug, locale: "bg") {
    slug
    name
    body(format: JSON)
    datasheet { url mimeType }
  }
  siteSetting(locale: "bg") {
    siteName
    phone
  }
}

Езици#

Подайте locale на поле от първо ниво и всяка преведена стойност под него, включително във връзките, идва на този език, а при липса на езика по подразбиране. Без locale получавате езика по подразбиране. С псевдоними една заявка може да поиска два езика.

Чернови#

status: DRAFT чете работните копия. Изисква ключ ck_prev_; с ключ ck_pub_ заявката завършва с грешка FORBIDDEN. Свързаните записи винаги са в публикуваната си версия.

GraphQL
# Needs a ck_prev_ key; with a ck_pub_ key this is a FORBIDDEN error
query Drafts {
  products(status: DRAFT, sort: { field: updatedAt, direction: DESC }) {
    data { slug updatedAt name }
  }
}

Автоматични persisted queries#

Изпратете extensions.persistedQuery.sha256Hash (SHA-256 на текста на заявката в шестнадесетичен вид) вместо самата заявка. Ако API познава хеша, изпълнява запазената заявка; ако не, отговаря с PERSISTED_QUERY_NOT_FOUND и статус 200, а вие изпращате заявката веднъж заедно с хеша. Запазените заявки се пазят 24 часа за всяко работно пространство. Хеш, който не отговаря на заявката, връща 400 PERSISTED_QUERY_HASH_MISMATCH.

# 1. Ask by hash only (a GET, so a CDN can cache it)
curl -G https://api.console.citronos.com/graphql \
  -H "Authorization: Bearer $CITRON_API_KEY" \
  --data-urlencode 'variables={"n":10}' \
  --data-urlencode 'extensions={"persistedQuery":{"version":1,"sha256Hash":"9d26ad0be5e0f576dba38d7c8579002c6c89e13f114bd8565dd622081ce7a346"}}'
# → {"errors":[{"message":"PersistedQueryNotFound","extensions":{"code":"PERSISTED_QUERY_NOT_FOUND"}}]}

# 2. Not known yet: send the query once with its hash; it is kept for 24 hours
curl https://api.console.citronos.com/graphql \
  -H "Authorization: Bearer $CITRON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"query ($n: Int) { products(pageSize: $n) { data { slug } meta { total } } }","variables":{"n":10},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"9d26ad0be5e0f576dba38d7c8579002c6c89e13f114bd8565dd622081ce7a346"}}}'

Кеширане#

Успешните отговори към ключове ck_pub_ се кешират от API за 60 секунди и идват с Cache-Control: public, max-age=60, stale-while-revalidate=300, ETag (така If-None-Match дава 304) и Vary: Authorization, x-api-key, Accept. Отговорите към ключове за преглед са no-store, а отговорите с грешки никога не се пазят в кеша на API.

Ограничения за дълбочина и сложност#

Заявката може да е дълбока най-много 6 нива и да струва най-много 1000. Поле-обект струва 1, поле-списък 1 плюс 10 пъти избраното в него, а скаларните полета и интроспекцията са безплатни. Над някое от ограниченията заявката се отхвърля, преди да се изпълни, с QUERY_TOO_DEEP или QUERY_TOO_COMPLEX.

GraphQL
# Cost: every list multiplies what is inside it by 10
# products 1 + data (1 + 10 × related (1 + 10 × related (1 + 10 × related (1)))) = 1112
query TooWide {
  products {
    data { related { related { related { slug } } } }
  }
}
Отговор (без locations)
{
  "errors": [
    {
      "message": "Query complexity 1112 exceeds the limit of 1000",
      "extensions": { "code": "QUERY_TOO_COMPLEX", "complexity": 1112, "limit": 1000 }
    }
  ]
}

Грешки#

extensions.codeКога
BAD_USER_INPUTНепознато поле или оператор във филтъра, твърде много филтри, непознат език, поле за един запис без id или slug.
FORBIDDENstatus: DRAFT с ключ ck_pub_.
QUERY_TOO_DEEP, QUERY_TOO_COMPLEXНад ограниченията по-горе.
PERSISTED_QUERY_NOT_FOUNDНепознат хеш: изпратете заявката заедно с него.
PERSISTED_QUERY_HASH_MISMATCHХешът не е SHA-256 на заявката (HTTP 400).

Грешките на ниво HTTP (лош ключ, изключен модул, ограничение на заявките) са като при REST; вижте грешки.

Справочникът описва само публичното API и следва договора му за съвместимост: публичните отговори само получават нови полета. Описанието на тези адреси във формат OpenAPI е на /developers/openapi.json.