Public API, Search & Caching
Step-by-step guide to exposing public read-only endpoints, field allowlists, full-text search indexing, and SWR tag-based caching.
Content Engine allows exposing read-only endpoints to your web frontend while keeping administrative data private.
Prerequisites & Context
Public read access requires a content type definition (e.g. articleContentType in src/content/article.ts) compiled into a server model articleContent in src/database/articles.ts:
import { createContentModel } from '@vitnode/core/content/server'
import { articleContentType } from '@/content/article'
export const articleContent = createContentModel(articleContentType)- Field Allowlisting: By default, no fields are exposed publicly. You must explicitly declare
publicApi.fields. buildContentPublicModule: An API plugin module from@vitnode/core/content/serverthat mounts public endpoints at/api/{plugin}/{entity}.
Step-by-Step Implementation
Step 1: Configure Public API Field Allowlist
In src/content/article.ts, add publicApi and list fields allowed for public reads:
export const articleContentType = defineContentType({
id: 'example.article',
tableName: 'example_articles',
publication: true,
publicApi: {
fields: ['title', 'code', 'excerpt', 'publishedAt', 'author'],
},
fields: {
title: field.text({ required: true }),
code: field.text({ required: true }),
excerpt: field.textarea({ nullable: true }),
adminNotes: field.textarea({ nullable: true }), // Excluded from public API
},
})Step 2: Register Public API Module
Attach buildContentPublicModule at the root level of your API plugin configuration:
import { buildContentPublicModule } from '@vitnode/core/content/server'
import { articleContent } from '@/database/articles'
export const exampleApiPlugin = () =>
buildApiPlugin({
pluginId: CONFIG_PLUGIN.pluginId,
modules: [
adminModule,
buildContentPublicModule({
pluginId: CONFIG_PLUGIN.pluginId,
contentTypes: [articleContent],
}),
],
})This creates:
GET /api/example/articles: Paginated list of published articles.GET /api/example/articles/[id]: Single published article details.
Step 3: Enable Global Search Indexing
Add search options to automatically sync items with the global search index:
export const articleContentType = defineContentType({
id: 'example.article',
tableName: 'example_articles',
search: {
titleField: 'title',
textField: 'excerpt',
},
fields: {
title: field.text({ required: true }),
excerpt: field.textarea({ nullable: true }),
},
})Step 4: Manage SWR Cache Tags in Server Actions
Use VitNode's cache helpers to invalidate or revalidate tags inside Server Actions:
'use server'
import { revalidateTag, updateTag } from '@vitnode/core/cache'
export async function updateArticleAction(id: number, data: unknown) {
// Perform update...
// Revalidate SWR list and item tags
revalidateTag(`content-public-item-example-article-${id}`, 'max')
updateTag(`user-${userId}`)
}Publication & Editorial
Add draft/published lifecycles, revision histories, signed preview links, and scheduled publishing to content types.
Localization & Translations
Step-by-step guide to building multi-language content models with localized fields, translation tables, independent workflows, and localized public APIs.