API de entrega GraphQL
Qué consultas existen, cómo funciona el acotado por workspace y cuáles envuelve el SDK frente a las que escribes tú.
cmssy sirve contenido publicado por un único endpoint GraphQL. El SDK ya envuelve las lecturas habituales -páginas, layouts, configuración del sitio, formularios-, así que la mayoría de apps nunca escribe una consulta. Para lo demás (modelos propios, registros, listar páginas hijas) envías la tuya por el cliente de entrega.
Endpoint y acotado
Las lecturas públicas van a la ruta con organización:
{apiBase}/public/{orgSlug}/{workspaceSlug}/graphqlapiBase es tu apiUrl sin el /graphql final: por defecto https://api.cmssy.io, así que las peticiones aterrizan en https://api.cmssy.io/public/{org}/{ws}/graphql. Sobrescribe apiUrl solo si te auto-alojas. org y workspaceSlug vienen de tu configuración y el SDK arma la ruta por ti.
Como la organización va en la ruta, un slug de workspace solo tiene que ser único dentro de su organización.
Dos formas de acotar una consulta
Toda operación está acotada al workspace, pero no todas del mismo modo. Este es el detalle con el que la gente tropieza:
workspaceSlug(String!): para lecturas de páginas, layouts, configuración y formularios. Los helpers del SDK lo pasan automáticamente desde tu configuración.workspaceId(String!): para lecturas de modelos, registros y páginas por tipo. Llama aclient.queryScoped(...): si tu consulta declara$workspaceIdy no lo pasas, el SDK lo resuelve desdeworkspaceSluge inyecta la variable y la cabecerax-workspace-id.
// $workspaceId se rellena por ti
await client.queryScoped(MY_QUERY, { modelSlug: "products", limit: 20 });Lo que el SDK ya envuelve
Normalmente nunca escribes estas: el helper indicado las llama por ti.
publicPage→fetchPage: devuelve{ id, blocks, publishedBlocks }.publicPageById→fetchPageById: devuelve{ id, publishedBlocks }.publicPages→fetchPages: devuelve[{ id, slug, updatedAt, publishedAt }].publicPage(campos SEO) →fetchPageMeta: devuelve{ id, seoTitle, seoDescription, seoKeywords, displayName }.publicPageLayouts→fetchLayouts: devuelve[{ position, blocks }].publicSiteConfig→fetchSiteConfig/resolveSiteLocales: nombre del sitio, locales, funciones, branding.public.form.get→resolveForms(ycontext.forms): campos y ajustes del formulario.public.form.submit→SUBMIT_FORM_MUTATION: devuelve{ success, message, submissionId, ... }.
Estas las escribes tú
No tienen helper en el SDK. Envíalas por client.queryScoped(...).
Registros de modelos propios
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
}
}
}
}Escribe la consulta tú y guárdala en tu repositorio. El SDK sí lleva cadenas equivalentes, pero bajo @cmssy/core/internal: una subruta interna, lo que significa que puede cambiar entre versiones sin nota de cambio incompatible. Tu propia consulta ocupa cuatro líneas y nunca te sorprende.
Listar páginas hijas
Esto es lo que alimenta un índice de blog o un árbol de documentación:
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
}
}Enviar un formulario
mutation SubmitForm($formId: ID!, $input: SubmitFormInput!) {
public {
form {
submit(formId: $formId, input: $input) {
success
message
submissionId
redirectUrl
}
}
}
}Exportada como SUBMIT_FORM_MUTATION. Pasa { formId, input: { data } }.
Auth de miembros: no la llames directamente
Las mutaciones siteMember -login, register, refresh, logout, forgotPassword, resetPassword, verifyEmail- sostienen el flujo de autenticación de miembros.
No las llames desde tu propio código. Monta createCmssyAuthRoute en su lugar: las gestiona en servidor y sella la cookie de sesión. Llamarlas directamente significa encargarte tú del sellado de tokens, y equivocarse ahí es un fallo de seguridad, no una página rota.
Cosas que conviene saber
datayfilterusan el escalarJSON: pasa objetos planos, no JSON en cadena.customFieldsen una página es un mapaJSONde los campos propios de ese tipo de página.- Las lecturas devuelven solo contenido publicado, salvo que se aporte un
previewSecretválido. El SDK lo hace por ti en modo edición con tudraftSecret.
Siguientes pasos
- Servidor MCP: la vía de escritura.
- Loaders de servidor: donde suelen vivir las consultas propias.
- Autenticación de miembros: el flujo tras las mutaciones
siteMember.