Better Blog

API routes

Expose CRUD endpoints and use the default API-backed provider

Better Blog can expose API endpoints and consume them via a default API-backed provider.

1) Mount the API router

Can be served by any web standard compatible server (like Bun, node, nextjs, sveltekit, etc...)

Create app/api/posts/[[...all]]/route.ts:

import { createBlogApiRouter } from "better-blog/api"
import { createSeededMemoryProvider } from "better-blog/providers/memory"

// simple in-memory provider for demo purposes, replace with your own provider
const provider = await createSeededMemoryProvider()

const { handler } = createBlogApiRouter({
  provider,
  openapi: { disabled: false },
});
  
  export const GET = handler;
  export const POST = handler;
  export const PUT = handler;
  export const DELETE = handler;

Or with TanStack Start, create src/routes/api/posts/$.ts:

import { createServerFileRoute } from "@tanstack/react-start/server"
import { createBlogApiRouter } from "better-blog/api"
import { createSeededMemoryProvider } from "better-blog/providers/memory"

const provider = await createSeededMemoryProvider()

const { handler } = createBlogApiRouter({
  provider,
  basePath: '/api/posts', // must match your api route path
  openapi: { disabled: false },
});


export const ServerRoute = createServerFileRoute("/api/posts/$").methods({
    GET: async ({ request }) => {
        return handler(request)
      },
      POST: async ({ request }) => {
        return handler(request)
      },
      PUT: async ({ request }) => {
        return handler(request)
      },
      DELETE: async ({ request }) => {
        return handler(request)
      },
  })

Endpoints exposed:

  • GET /api/posts/posts – list (supports slug, tag, offset, limit, query, published, locale)
  • GET /api/posts/posts/:slug – fetch one (supports locale via query)
  • POST /api/posts/posts – create
  • PUT /api/posts/posts/:slug – update
  • DELETE /api/posts/posts/:slug – delete

Locale support

  • The API supports a locale query param for both list and detail routes.
  • On the client, the API-backed provider is wired through BlogProvider (not used standalone).
  • You can set a provider-wide defaultLocale and optionally override per call via the context’s dataProvider.

Usage with context:

import { BlogProvider } from "better-blog/context";

// Provide API-backed client via built-in API provider
<BlogProvider apiBasePath="/api/posts">
  {children}
</BlogProvider>