Referință

GraphQL API

Același conținut publicat ca în REST API, printr-un singur punct de acces, cu o schemă construită din colecțiile dumneavoastră. Relațiile se rezolvă în aceeași cerere.

Punct de acces#

POST/graphql

Rulează o interogare cu un corp JSON { query, variables, operationName, extensions }.

GET/graphql

La fel, dar cu câmpurile trimise ca parametri de interogare (variables și extensions codificate ca JSON). Util în spatele unui CDN.

Calea nu conține /v1: este https://api.console.citronos.com/graphql. Acceptă aceleași chei ca REST (ck_pub_ pentru conținutul publicat, ck_prev_ pentru ciorne) în Authorization: Bearer … sau x-api-key și împarte cu acestea limita de cereri per cheie.

GraphQL este un modul pe care îl activați pentru spațiul de lucru, inclus începând cu planul Professional. Cât timp este dezactivat, /graphql răspunde cu 404 pentru cheile acelui spațiu de lucru.

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}}'

Schema dumneavoastră#

Fiecare spațiu de lucru are propria schemă, reconstruită la fiecare modificare a unei colecții. Introspecția funcționează cu orice cheie validă, așa că GraphiQL, instrumentele Apollo sau graphql-codegen o pot citi. Numele provin din slug-urile colecțiilor:

Slug-ul colecțieiTipCâmp de listăCâmp individual
productsProductproducts(…): ProductList!product(id, slug, …): Product
other-productsOtherProductotherProductsotherProduct
galleryGallerygalleryListgallery
site-settings (instanță unică)SiteSettingniciunulsiteSetting(…): SiteSetting
  • Fiecare tip de înregistrare are id, slug, publishedAt, updatedAt și sortOrder, apoi câte un câmp pentru fiecare câmp al colecției.
  • Un câmp de listă returnează { data: [Entry!]!, meta: PageMeta! }, cu total, page, pageSize și pageCount în meta.
  • Câmpurile de imagine și media sunt obiecte Asset (url, width, height, alt, variants, focal), relațiile au tipul înregistrării asociate, iar textul formatat este un String cu argumentul format: HTML | JSON (JSON-ul vine ca șir de caractere).
  • Un câmp individual returnează null când înregistrarea nu există, în loc de o eroare.
  • Colecțiile live (externe) nu apar în schemă. Nu există mutații sau subscripții.

Filtre, sortare și paginare#

Câmpurile de listă acceptă filter, sort, page, pageSize (cel mult 100), locale și status. Filtrele urmează modelul REST: StringFilter și FloatFilter au eq ne lt lte gt gte in notIn (șirurile adaugă contains), BooleanFilter are eq ne, iar câmpurile de tip listă acceptă ListFilter { contains }. Cel mult 10 condiții. sort este un singur { 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
  }
}

Limbi#

Transmiteți locale pe un câmp rădăcină și fiecare valoare localizată de sub acesta, inclusiv din relații, vine în limba respectivă, cu limba implicită ca rezervă. Fără locale primiți limba implicită. Cu ajutorul alias-urilor, o singură cerere poate solicita două limbi.

Ciorne#

status: DRAFT citește copiile de lucru. Necesită o cheie ck_prev_; cu o cheie ck_pub_ interogarea eșuează cu eroarea FORBIDDEN. Înregistrările asociate se rezolvă întotdeauna la versiunea lor publicată.

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 automate#

Trimiteți extensions.persistedQuery.sha256Hash (SHA-256 hexazecimal al textului interogării) în locul interogării. Dacă API-ul cunoaște hash-ul, rulează interogarea stocată; dacă nu, răspunde cu PERSISTED_QUERY_NOT_FOUND și statusul 200, iar dumneavoastră trimiteți interogarea o singură dată, împreună cu hash-ul. Interogările stocate sunt păstrate 24 de ore pentru fiecare spațiu de lucru. Un hash care nu corespunde interogării primește 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"}}}'

Cache#

Răspunsurile reușite pentru cheile ck_pub_ sunt păstrate în cache de API timp de 60 de secunde și includ Cache-Control: public, max-age=60, stale-while-revalidate=300, un ETag (astfel, If-None-Match produce un 304) și Vary: Authorization, x-api-key, Accept. Răspunsurile pentru cheile de previzualizare sunt no-store, iar răspunsurile cu erori nu sunt niciodată păstrate în cache-ul API-ului.

Limite de adâncime și complexitate#

O interogare poate avea cel mult 6 niveluri de adâncime și un cost de cel mult 1.000. Un câmp de tip obiect costă 1, un câmp de tip listă costă 1 plus de 10 ori ceea ce selectează, iar câmpurile scalare și introspecția sunt gratuite. Dacă depășește oricare dintre limite, interogarea este respinsă înainte de execuție, cu QUERY_TOO_DEEP sau 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 } } } }
  }
}
Response (locations omitted)
{
  "errors": [
    {
      "message": "Query complexity 1112 exceeds the limit of 1000",
      "extensions": { "code": "QUERY_TOO_COMPLEX", "complexity": 1112, "limit": 1000 }
    }
  ]
}

Erori#

extensions.codeCând
BAD_USER_INPUTUn câmp sau un operator de filtrare necunoscut, prea multe filtre, o limbă necunoscută, un câmp individual fără id sau slug.
FORBIDDENstatus: DRAFT cu o cheie ck_pub_.
QUERY_TOO_DEEP, QUERY_TOO_COMPLEXDepășirea limitelor de mai sus.
PERSISTED_QUERY_NOT_FOUNDHash necunoscut: trimiteți interogarea împreună cu el.
PERSISTED_QUERY_HASH_MISMATCHHash-ul nu este SHA-256 al interogării (HTTP 400).

Erorile de transport (o cheie greșită, modulul dezactivat, limita de cereri) sunt erori HTTP, ca în REST; consultați erorile.

Această referință acoperă doar API-ul public și respectă contractul de compatibilitate al API-ului: răspunsurile publice pot doar să primească câmpuri noi. Descrierea OpenAPI a acestor rute se află la /developers/openapi.json.