Skip to content

GraphQL API

WollyCMS provides a GraphQL API alongside the REST API. Both return the same data — use whichever fits your workflow.

Endpoint: POST /api/content/graphql (or GET /api/content/graphql?query=...)

No authentication required — the GraphQL API is read-only and returns only published content (same as the REST content API).

Fetch a page with its blocks and a menu in one request:

{
page(slug: "about") {
title
slug
locale
seo { metaTitle, metaDescription }
regions
translations { locale, slug, title }
}
menu(slug: "main-navigation") {
items {
title
url
pageSlug
children { title, url }
}
}
}

List published pages with filtering.

{
pages(type: "article", locale: "en", limit: 10, offset: 0, sort: "published_at:desc") {
data {
id, title, slug, type, locale
fields
meta { createdAt, updatedAt, publishedAt }
}
meta { total, limit, offset }
}
}

Arguments:

ArgumentTypeDefaultDescription
typeStringFilter by content type slug
localeStringdefault localeFilter by locale
sortStringpublished_at:descSort field and direction
limitInt20Max results (capped at 50)
offsetInt0Pagination offset

Get a single page by slug with blocks, SEO, and translations.

{
page(slug: "about", locale: "en") {
id
title
slug
type
locale
translationGroupId
translations {
id, locale, slug, title
}
fields
seo {
metaTitle
metaDescription
ogImage
canonicalUrl
robots
}
regions
meta {
createdAt
updatedAt
publishedAt
}
}
}

The regions field returns JSON with blocks grouped by region:

{
"hero": [{ "block_type": "hero", "fields": { "heading": "..." } }],
"content": [{ "block_type": "rich_text", "fields": { "body": "..." } }]
}

Get a menu with nested items.

{
menu(slug: "main-navigation") {
id
name
items {
title
url
pageSlug
target
depth
children {
title
url
pageSlug
}
}
}
}

List all menus (without items — fetch individually for items).

{
menus {
id, name, slug
}
}
{
taxonomy(slug: "tags") {
name
hierarchical
terms {
id, name, slug, weight
}
}
taxonomies {
name, slug, hierarchical
}
}
{
config {
siteName
tagline
logo
defaultLocale
supportedLocales
}
}
const response = await fetch('https://cms.example.com/api/content/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `{
pages(type: "article", limit: 5) {
data { title, slug, fields }
}
}`
}),
});
const { data } = await response.json();
const query = `
query GetPage($slug: String!, $locale: String) {
page(slug: $slug, locale: $locale) {
title, regions, seo { metaTitle, metaDescription }
}
}
`;
const response = await fetch('/api/content/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables: { slug: 'about', locale: 'en' } }),
});
RESTGraphQL
EndpointMultiple (/pages, /menus, etc.)Single (/graphql)
Data fetchingFixed response shapeRequest exactly what you need
Multiple resourcesMultiple requestsOne query
CachingHTTP cache headers + ETagsApplication-level
Best forSimple fetches, Astro SSRComplex queries, AI tooling, data migration

Both APIs return the same data and stay in sync. Use REST for standard Astro pages, GraphQL for complex queries or when you need multiple resources in one request.