API dostawcze GraphQL
Jakie zapytania istnieją, jak działa scoping workspace'u i które odczyty opakowuje SDK, a które piszesz sam.
cmssy serwuje opublikowaną treść przez jeden endpoint GraphQL. SDK opakowuje już typowe odczyty - strony, layouty, konfigurację serwisu, formularze - więc większość aplikacji nigdy nie pisze zapytania. Do reszty (własne modele, rekordy, listowanie stron potomnych) wysyłasz własne przez klienta dostawczego.
Endpoint i scoping
Publiczne odczyty idą na ścieżkę z organizacją:
{apiBase}/public/{orgSlug}/{workspaceSlug}/graphqlapiBase to Twoje apiUrl z obciętym końcowym /graphql - domyślnie https://api.cmssy.io, więc żądania lądują na https://api.cmssy.io/public/{org}/{ws}/graphql. Nadpisuj apiUrl tylko przy self-hoście. org i workspaceSlug pochodzą z Twojej konfiguracji, a SDK składa ścieżkę za Ciebie.
Ponieważ organizacja siedzi w ścieżce, slug workspace'u musi być unikalny tylko w obrębie swojej organizacji.
Dwa sposoby ograniczenia zapytania
Każda operacja jest ograniczona do workspace'u, ale nie wszystkie tak samo. To ten szczegół, na którym ludzie się wykładają:
workspaceSlug(String!) - używany przez odczyty stron, layoutów, konfiguracji i formularzy. Helpery SDK podają go automatycznie z Twojej konfiguracji.workspaceId(String!) - używany przez odczyty modeli, rekordów i stron po typie. Wywołajclient.queryScoped(...): gdy Twoje zapytanie deklaruje$workspaceId, a Ty go nie podasz, SDK rozwiąże je zworkspaceSlugi wstrzyknąć zarówno zmienną, jak i nagłówekx-workspace-id.
// $workspaceId zostaje uzupełnione za Ciebie
await client.queryScoped(MY_QUERY, { modelSlug: "products", limit: 20 });Co SDK już opakowuje
Normalnie nigdy tego nie piszesz - wymieniony helper wywołuje to za Ciebie.
publicPage→fetchPage- zwraca{ id, blocks, publishedBlocks }.publicPageById→fetchPageById- zwraca{ id, publishedBlocks }.publicPages→fetchPages- zwraca[{ id, slug, updatedAt, publishedAt }].publicPage(pola SEO) →fetchPageMeta- zwraca{ id, seoTitle, seoDescription, seoKeywords, displayName }.publicPageLayouts→fetchLayouts- zwraca[{ position, blocks }].publicSiteConfig→fetchSiteConfig/resolveSiteLocales- nazwa serwisu, locale, funkcje, branding.public.form.get→resolveForms(orazcontext.forms) - pola i ustawienia formularza.public.form.submit→SUBMIT_FORM_MUTATION- zwraca{ success, message, submissionId, ... }.
Te napiszesz sam
Nie mają helpera w SDK. Wyślij je przez client.queryScoped(...).
Rekordy własnych modeli
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
}
}
}
}Napisz zapytanie sam i trzymaj je w swoim repo. SDK ma odpowiedniki tych stringów, ale pod @cmssy/core/internal - to podscieżka wewnętrzna, co znaczy, że może się zmienić między wydaniami bez adnotacji o breaking change. Twoje własne zapytanie ma cztery linijki i nigdy Cię nie zaskoczy.
Listowanie stron potomnych
To jest to, co napędza indeks bloga albo drzewo docsów:
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
}
}Wysłanie formularza
mutation SubmitForm($formId: ID!, $input: SubmitFormInput!) {
public {
form {
submit(formId: $formId, input: $input) {
success
message
submissionId
redirectUrl
}
}
}
}Eksportowane jako SUBMIT_FORM_MUTATION. Przekaż { formId, input: { data } }.
Autoryzacja członków: nie wywołuj bezpośrednio
Mutacje siteMember - login, register, refresh, logout, forgotPassword, resetPassword, verifyEmail - stoją za przepływem logowania członków.
Nie wywołuj ich z własnego kodu. Zamiast tego zamontuj createCmssyAuthRoute: obsługuje je po stronie serwera i pieczętuje ciasteczko sesji. Wywoływanie ich wprost oznacza, że sam ogarniasz pieczętowanie tokenów, a pomyłka tutaj to błąd bezpieczeństwa, nie zepsuta strona.
Warto wiedzieć
dataifilterużywają skalaraJSON- przekazuj zwykłe obiekty, nie JSON jako string.customFieldsna stronie to mapaJSONpól własnych danego typu strony.- Odczyty zwracają wyłącznie treść opublikowaną, chyba że podano prawidłowy
previewSecret. SDK robi to za Ciebie w trybie edycji, używając TwojegodraftSecret.
Następne kroki
- Serwer MCP - ścieżka zapisu.
- Loadery serwerowe - tam zwykle żyją własne zapytania.
- Autoryzacja członków - przepływ stojący za mutacjami
siteMember.