Désormais avec création de pages par IA via le serveur MCP

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 encapsule déjà

Vous n'écrivez normalement jamais ces requêtes : le helper indiqué les appelle pour vous.

  • publicPagefetchPage - renvoie { id, blocks, publishedBlocks }.
  • publicPageByIdfetchPageById - renvoie { id, publishedBlocks }.
  • publicPagesfetchPages - renvoie [{ id, slug, updatedAt, publishedAt }].
  • publicPage (champs SEO) → fetchPageMeta - renvoie { id, seoTitle, seoDescription, seoKeywords, displayName }.
  • publicPageLayoutsfetchLayouts - renvoie [{ position, blocks }].
  • publicSiteConfigfetchSiteConfig / resolveSiteLocales - nom du site, locales, fonctionnalités, branding.
  • public.form.getresolveForms (et context.forms) - champs et réglages du formulaire.
  • public.form.submitSUBMIT_FORM_MUTATION - renvoie { success, message, submissionId, ... }.

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
) {
  publicPagesByType(
    workspaceId: $workspaceId
    parentSlug: $parentSlug
    search: $search
    limit: $limit
    offset: $offset
  ) {
    items {
      id
      slug
      fullSlug
      publishedAt
      displayName
      seoTitle
      seoDescription
      customFields
      pageType
    }
    total
    hasMore
  }
}

Soumettre un formulaire

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

Exportée sous le nom SUBMIT_FORM_MUTATION. Passez { formId, input: { data } }.

Auth des membres : ne pas appeler directement

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

Ne les appelez pas depuis votre propre code. Montez plutôt createCmssyAuthRoute : il les gère côté serveur et scelle le cookie de session. Les appeler directement revient à gérer vous-même le scellement des jetons, et s'y tromper est une faille de sécurité, pas une page cassée.

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