Αναφορά

GraphQL API

Το ίδιο δημοσιευμένο περιεχόμενο με το REST API, μέσω ενός μόνο σημείου πρόσβασης και με σχήμα που χτίζεται από τις συλλογές σας. Οι συσχετίσεις επιλύονται στην ίδια αίτηση.

Σημείο πρόσβασης#

POST/graphql

Εκτελεί ένα ερώτημα με σώμα JSON { query, variables, operationName, extensions }.

GET/graphql

Το ίδιο, με τα πεδία ως παραμέτρους του URL (τα 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}}'

Το σχήμα σας#

Κάθε χώρος εργασίας έχει το δικό του σχήμα, που χτίζεται ξανά όταν αλλάζει μια συλλογή. Η ενδοσκόπηση (introspection) λειτουργεί με οποιοδήποτε έγκυρο κλειδί, οπότε το 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! }, με total, page, pageSize και pageCount στο meta.
  • Τα πεδία εικόνας και πολυμέσων είναι αντικείμενα Asset (url, width, height, alt, variants, focal), οι συσχετίσεις έχουν τον τύπο της συσχετισμένης εγγραφής και το μορφοποιημένο κείμενο είναι String με όρισμα format: HTML | JSON (το JSON ως συμβολοσειρά).
  • Ένα πεδίο μίας εγγραφής επιστρέφει null όταν η εγγραφή δεν υπάρχει, αντί για σφάλμα.
  • Οι ζωντανές (εξωτερικές) συλλογές δεν περιλαμβάνονται στο σχήμα. Δεν υπάρχουν mutations ούτε subscriptions.

Φίλτρα, ταξινόμηση και σελιδοποίηση#

Τα πεδία λίστας δέχονται 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 λαμβάνετε την προεπιλεγμένη γλώσσα. Με ψευδώνυμα (aliases), μία αίτηση μπορεί να ζητήσει δύο γλώσσες.

Πρόχειρα#

Το 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 γνωρίζει το hash, εκτελεί το αποθηκευμένο ερώτημα· αν όχι, απαντά PERSISTED_QUERY_NOT_FOUND με κατάσταση 200 και εσείς στέλνετε το ερώτημα μία φορά μαζί με το hash. Τα αποθηκευμένα ερωτήματα διατηρούνται 24 ώρες ανά χώρο εργασίας. Ένα hash που δεν αντιστοιχεί στο ερώτημα λαμβάνει απάντηση 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 επίπεδα και κόστος έως 1.000. Ένα πεδίο αντικειμένου κοστίζει 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 } } } }
  }
}
Response (locations omitted)
{
  "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Άγνωστο hash: στείλτε το ερώτημα μαζί του.
PERSISTED_QUERY_HASH_MISMATCHΤο hash δεν είναι το SHA-256 του ερωτήματος (HTTP 400).

Τα σφάλματα μεταφοράς (λανθασμένο κλειδί, απενεργοποιημένη μονάδα, όριο αιτήσεων) είναι σφάλματα HTTP, όπως στο REST· δείτε τα σφάλματα.

Αυτή η αναφορά καλύπτει μόνο το δημόσιο API και ακολουθεί τη σύμβαση συμβατότητας του API: οι δημόσιες αποκρίσεις μόνο αποκτούν νέα πεδία. Η περιγραφή OpenAPI αυτών των διαδρομών βρίσκεται στο /developers/openapi.json.