API de diffusion GraphQL

Quelles requêtes existent, comment fonctionne le cadrage par espace de travail, et lesquelles le SDK encapsule plutôt que vous.

cmssy sert le contenu publié via un unique endpoint GraphQL. Le SDK encapsule déjà les lectures courantes - pages, layouts, configuration du site, formulaires - si bien que la plupart des applications n'écrivent jamais de requête. Pour le reste (modèles personnalisés, enregistrements, listes de pages enfants), vous envoyez la vôtre via le client de diffusion.

Endpoint et cadrage

Les lectures publiques passent par le chemin incluant l'organisation :

{apiBase}/public/{orgSlug}/{workspaceSlug}/graphql

apiBase est votre apiUrl privé de son /graphql final - par défaut https://api.cmssy.io, les requêtes arrivent donc sur https://api.cmssy.io/public/{org}/{ws}/graphql. Ne redéfinissez apiUrl qu'en auto-hébergement. org et workspaceSlug viennent de votre configuration, et le SDK assemble le chemin.

Comme l'organisation figure dans le chemin, un slug d'espace de travail ne doit être unique qu'au sein de son organisation.

Deux façons de cadrer une requête

Chaque opération est cadrée par espace de travail, mais pas toutes de la même manière. C'est le détail sur lequel on trébuche :

  • workspaceSlug (String!) - pour les lectures de pages, layouts, configuration et formulaires. Les helpers du SDK le transmettent automatiquement depuis votre configuration.
  • workspaceId (String!) - pour les lectures de modèles, d'enregistrements et de pages par type. Appelez client.queryScoped(...) : si votre requête déclare $workspaceId et que vous ne le passez pas, le SDK le résout depuis workspaceSlug et injecte la variable et l'en-tête x-workspace-id.
// $workspaceId est rempli pour vous
await client.queryScoped(MY_QUERY, { modelSlug: "products", limit: 20 });

Ce que le SDK lit déjà pour vous

Vous n'écrivez normalement jamais ces requêtes : createCmssyPage, CmssyServerLayout et la résolution des formulaires derrière context.forms les émettent en interne.

  • public.page.get - une page par slug : { id, blocks, publishedBlocks } plus les champs SEO seoTitle, seoDescription, seoKeywords, displayName.
  • public.page.getById - { id, publishedBlocks }.
  • public.page.list - [{ id, slug, updatedAt, publishedAt }].
  • public.page.layouts - [{ position, blocks, settings }].
  • public.siteConfig - nom du site, langue par défaut et langues activées, fonctionnalités, branding.
  • public.form.get - champs et réglages du formulaire, exposés aux blocs via context.forms.
  • public.form.submit - { success, message, submissionId, redirectUrl }.

Les helpers qui les encapsulent - fetchPage, fetchPages, fetchLayouts, fetchPageMeta, fetchSiteConfig, resolveSiteLocales, resolveForms - vivent sous @cmssy/core/internal et ne font pas partie de l'API publique. La surface publique, ce sont createCmssyClient et graphqlRequest : tout ce que createCmssyPage ne rend pas déjà, vous l'interrogez vous-même.

Celles-ci, à vous de les écrire

Elles n'ont pas de helper SDK. Envoyez-les via client.queryScoped(...).

Enregistrements de modèles personnalisés

query PublicModelRecords(
  $workspaceId: String!
  $modelSlug: String!
  $filter: JSON
  $sort: String
  $limit: Int
  $offset: Int
  $populate: [String!]
) {
  public {
    model {
      records(
        workspaceId: $workspaceId
        modelSlug: $modelSlug
        filter: $filter
        sort: $sort
        limit: $limit
        offset: $offset
        populate: $populate
      ) {
        items { id modelId data status createdAt updatedAt }
        total
        hasMore
      }
    }
  }
}

Écrivez la requête vous-même et gardez-la dans votre dépôt. Le SDK contient bien des chaînes équivalentes, mais sous @cmssy/core/internal - un sous-chemin interne, qui peut donc changer d'une version à l'autre sans mention de rupture. Votre propre requête tient en quatre lignes et ne vous surprendra jamais.

Lister les pages enfants

C'est ce qui alimente un index de blog ou une arborescence de documentation :

query PublicPagesByType(
  $workspaceId: String!
  $parentSlug: String
  $search: String
  $limit: Int
  $offset: Int
) {
  public {
    page {
      byType(
        workspaceId: $workspaceId
        parentSlug: $parentSlug
        search: $search
        limit: $limit
        offset: $offset
      ) {
        items {
          id
          slug
          fullSlug
          publishedAt
          displayName
          seoTitle
          seoDescription
          customFields
          pageType
        }
        total
        hasMore
      }
    }
  }
}

byType accepte aussi pageType, sortBy et customFieldFilters, et - avec un previewSecret valide - includeDrafts.

Soumettre un formulaire

mutation SubmitForm($formId: ID!, $input: SubmitFormInput!) {
  public {
    form {
      submit(formId: $formId, input: $input) {
        success
        message
        submissionId
        redirectUrl
      }
    }
  }
}

Passez { formId, input: { data } }. Le SDK porte la même chaîne sous le nom SUBMIT_FORM_MUTATION, mais dans @cmssy/core/internal : gardez votre propre copie plutôt que de l'importer.

L'auth des membres, c'est à vous de la monter

Les mutations siteMember - login, register, refresh, logout, forgotPassword, resetPassword, verifyEmail - portent le flux d'authentification des membres.

Le SDK allégé ne fournit ni route d'auth ni lecteur de session. login et refresh vous rendent les accessToken et refreshToken bruts, et le backend ne pose aucun cookie : la session appartient à votre application. Un cookie httpOnly écrit par votre propre route handler est le choix sûr par défaut. Le flux complet, de l'inscription à la vérification de l'e-mail, est décrit dans authentification des membres.

Bon à savoir

  • data et filter utilisent le scalaire JSON - passez des objets simples, pas du JSON en chaîne.
  • customFields sur une page est une map JSON des champs personnalisés de son type de page.
  • Les lectures ne renvoient que du contenu publié, sauf si un previewSecret valide est fourni. Le SDK s'en charge en mode édition avec votre draftSecret.

Étapes suivantes