Guides

Read content from a site

Read what you publish from a Worker over a service binding, from a Nuxt, Astro, React or Vue site, or from anywhere over HTTP with a read token.

Read content from a site

Your site reads published content only: a draft, or the unpublished changes of an entry, never reach it. There are three ways in.

From a Worker, over a service binding

A Worker on the same Cloudflare account binds the Hollware entrypoint of your Hollware Worker. No network, no token:

// wrangler.jsonc of the site
"services": [
  { "binding": "HOLLWARE", "service": "my-cms", "entrypoint": "Hollware" }
]
const answer = await env.HOLLWARE.getEntry('my-site', 'blog', 'hello-world', 'en', {
  formats: ['html'],
})
if (answer.outcome === 'ok') return new Response(answer.entry.html)

The binding has six methods, all read-only: getEntry, listEntries, getTranslations, describeSite, search and listRedirects. getEntry returns the Markdown, the Comark document or the HTML, as formats asks; with related: true the published entries closest to it by meaning, and with references: true the entries its reference fields name (an author, a series: see Contracts). Its images come with their srcset and size (Images), and the fields the collection has Hollware fill (a date, the reading time) come filled in its frontmatter (Configure your content).

const found = await env.HOLLWARE.search('my-site', 'how do I cache pages', { locale: 'en', limit: 5 })

search finds published entries by their words, by meaning, or both (mode: 'fulltext' | 'semantic' | 'hybrid', hybrid by default), and with passages: true the section of each that matched, for a model to answer with. Search by meaning needs Workers AI and Vectorize: see Search and analytics.

When an entry moves to another slug, its old path is kept as a redirect. Answer it with a 301:

const moved = await hollware.redirectFor('blog', 'en', slug) // createHollware() of any package
if (moved) return Response.redirect(new URL(moved.path ?? moved.slug, request.url), 301)

From a framework

Each framework has a package that reads Hollware and renders what it reads with your own components, with previews of drafts and images ready:

FrameworkPackageGuide
Nuxt@hollware/nuxtNuxt
Astro@hollware/astroAstro
React Router, Next.js, TanStack Start@hollware/reactReact
Vue 3 without Nuxt@hollware/vueVue

Any other JavaScript reads with @hollware/client, the package all of them build on: createHollware over a binding or a read token, and imageOf for the images of the frontmatter.

Over HTTP, with a read token

The read API serves the same reads at /v1:

curl -H "Authorization: Bearer hw_read_..." "http://localhost:5199/v1/blog/en/hello-world?formats=html"
RequestAnswer
GET /v1/sitethe site: locales, collections
GET /v1/search?q&collection&locale&limit&mode&passages&minScorethe published entries that match q, best first
GET /v1/{collection}?locale&tag&limit&cursora page of published entries
GET /v1/{collection}/{locale}/{slug}?formats=&related=&references=one entry, with its related entries and the entries it names when asked
GET /v1/{collection}/translations/{group}the entries of a translation group
GET /v1/redirects?collection&locale&limit&cursorthe old paths of the entries that moved, and where they go

Answers carry an ETag; send it back in If-None-Match to get a 304. The OpenAPI document is at /v1/openapi.json.

A read token (hw_read_) reads published content over this API and nothing else, so it can sit in a build, or even in a browser:

npx hollware token create --read --label my-site            # in the project, for the local database
npx hollware token create --read --label my-site --remote   # for the deployed one

Like every token, it is printed once: Hollware keeps only its hash. Locally the read API is at http://localhost:5199/v1; once deployed, at the public URL of your Hollware. blog is the starter's collection: use the names describe_site returns.

For a browser, list the origins of your pages in the admin, under Site, as Origins that read from the browser, such as https://example.com, or have an agent add them with update_site. They apply at once.