Content Delivery API (CDA)
Viglet Shio is headless-first: your content engine runs on Java/Spring Boot, but the sites and apps that consume it are pure JavaScript/TypeScript. The Content Delivery API (CDA) is the stable, read-only contract that JS clients depend on.
Shio (Java/Spring) ──/api/v2/cda/**──▶ @viglet/shio-client ──▶ Next.js / React / Vue / Astro / NodeWhat makes the CDA different from the console REST API
Section titled “What makes the CDA different from the console REST API”Console API (/api/v2/...) |
Content Delivery API (/api/v2/cda/**) |
|
|---|---|---|
| Purpose | Authoring (admin console) | Public delivery to sites/apps |
| Methods | Read and write | Read-only (GET) |
| Content | Drafts + published | Published only |
| Response | Rich internal models | Frozen, minimal DTOs |
| Auth | Session + CSRF | API token (Key header) |
The CDA never exposes drafts or authoring-only fields (owner, publisher,
publishStatus), and its response shape is frozen: safe to build a public
site on.
Authentication
Section titled “Authentication”The CDA is authenticated with an API token sent in the Key header. CDA
tokens are read-only: any non-GET request is rejected with 403.
curl https://cms.example.com/api/v2/cda/site \ -H "Key: <your-cda-token>"Create and manage tokens in the admin console (API Tokens). A token can sit safely behind a CDN or in a server-side environment (Next.js server components, Node).
Endpoints
Section titled “Endpoints”All endpoints are under /api/v2/cda, return application/json, and are GET only.
| Method | Path | Purpose |
|---|---|---|
| GET | /cda/site |
List published sites |
| GET | /cda/site/{siteId} |
One site (with root folder id) |
| GET | /cda/site/{siteId}/redirects |
The site’s redirects, ordered by from |
| GET | /cda/object/{folderId}/list?page&size |
A folder’s children (subfolders + posts) |
| GET | /cda/object/{id}/path |
Breadcrumb path for a folder or post |
| GET | /cda/post/{id} |
One published post (attributes expanded) |
| GET | /cda/post/by-url?siteId&url |
Resolve a published post by friendly URL |
| GET | /cda/query?siteId&folderId&postType&page&size |
Query published posts |
Unknown ids, unpublished content, or an unresolvable URL return 404. A draft
is never returned.
Resolve a page by URL
Section titled “Resolve a page by URL”The by-url endpoint powers catch-all routing (e.g. Next.js [...slug]):
curl "https://cms.example.com/api/v2/cda/post/by-url?siteId=SITE_ID&url=/blog/hello-world" \ -H "Key: <your-cda-token>"Redirects on a site with its own front end
Section titled “Redirects on a site with its own front end”A redirect you create in Viglet Shio (a Redirect post, or the offer to keep an old address
working when you rename a page) is served by Shio’s own /sites/** delivery. If your site is
rendered by its own front end, such as Next.js, visitors never pass through that delivery, so
the front end has to do the redirecting itself. This endpoint gives it the table:
curl "https://cms.example.com/api/v2/cda/site/SITE_ID/redirects" -H "Key: <your-cda-token>"[ { "from": "/about", "to": "https://example.org/about", "permanent": false }, { "from": "/pricing", "to": "/plans", "permanent": true }]fromis the path that moved andtois where it went: a path on the same site, or a full URL.permanent: truemeans answer with a301;falsemeans a302, which is the default.- A production token sees published redirects only. A preview token also sees drafts.
- The table is small and changes rarely, so fetch it once and cache it rather than asking on every
request. Consult it before answering
404.
Response shapes
Section titled “Response shapes”{ "id": "string", "name": "string", "description": "string | null", "url": "string | null", "rootFolderId": "string | null"}{ "id": "string", "title": "string | null", "summary": "string | null", "furl": "string | null", "postType": "string | null", "siteId": "string | null", "folderId": "string | null", "published": true, "date": "ISO-8601 | null", "modifiedDate": "ISO-8601 | null", "publicationDate": "ISO-8601 | null", "attrs": { "title": "Hello", "content": "<p>...</p>" }}attrs is the post’s field map, keyed by your post-type attribute names. A
malformed payload yields {} rather than an error.
Listing
Section titled “Listing”{ "folderId": "string | null", "folders": [{ "id": "string", "name": "string", "root": false }], "posts": [ { "id": "string", "title": "string | null", "summary": "string | null", "furl": "string | null", "postType": "string | null", "date": "ISO-8601 | null", "modifiedDate": "ISO-8601 | null" } ], "page": 0, "size": 50, "totalPosts": 0}Path (breadcrumb)
Section titled “Path (breadcrumb)”{ "site": { "...": "ShioSite" }, "breadcrumb": [{ "id": "string", "name": "string", "root": true }], "currentFolder": { "id": "string", "name": "string", "root": false }}The breadcrumb array is ordered root → … → current.
Next steps
Section titled “Next steps”- JavaScript Client: the framework-agnostic
@viglet/shio-client. - React SDK: hooks and render components.
- Next.js Starter:
npx create-shio-app.