jsonapi_frontend is a minimal Drupal module that makes JSON:API frontend-ready by adding a path → JSON:API URL resolver endpoint.
- Resolve frontend paths (including aliases) to JSON:API resource URLs
- Optional Redirect support (honors
redirectmodule; returns 301/302 info) - Hybrid headless: choose what your frontend renders vs what stays on Drupal
- Optional Views support via
jsonapi_views - Optional secret-protected routes feed (
/jsonapi/routes) for static builds (SSG) - Optional cache revalidation webhooks for frontend caches (Next.js, etc.)
- Optional menu endpoint (
/jsonapi/menu/{menu}) viajsonapi_frontend_menu
Documentation: https://www.drupal.org/docs/contributed-modules/jsonapi-frontend Issue queue: https://www.drupal.org/project/issues/jsonapi_frontend
- Drupal 10 or 11
- Core modules: JSON:API, Path Alias
Optional:
jsonapi_views(Views support)
composer require drupal/jsonapi_frontend
drush en jsonapi_frontendcurl "https://your-site.com/jsonapi/resolve?path=/about-us&_format=json"Typical successful entity resolution looks like:
{
"resolved": true,
"kind": "entity",
"jsonapi_url": "/jsonapi/node/page/…",
"headless": true
}npm i @codewheel/jsonapi-frontend-clientimport { resolvePath, fetchJsonApi } from "@codewheel/jsonapi-frontend-client"
const resolved = await resolvePath("/about-us")
if (resolved.resolved && resolved.kind === "entity") {
const doc = await fetchJsonApi(resolved.jsonapi_url)
console.log(doc.data)
}const resolved = await fetch(`${DRUPAL_BASE_URL}/jsonapi/resolve?path=${path}&_format=json`).then((r) => r.json())
if (resolved.resolved && resolved.kind === "entity") {
const doc = await fetch(`${DRUPAL_BASE_URL}${resolved.jsonapi_url}`).then((r) => r.json())
}- Next.js (routing + rendering + media helpers): https://github.com/code-wheel/jsonapi-frontend-next
- Astro (SSR + optional proxy middleware): https://github.com/code-wheel/jsonapi-frontend-astro
- Nuxt 3 + Remix recipes: see
MIGRATION.md
Configure at /admin/config/services/jsonapi-frontend.
Typical settings:
- Deployment mode (Split routing vs frontend-first)
- Drupal URL / origin + optional proxy secret
- Resolver cache max-age (anonymous-only)
- Resolver langcode fallback (
site_defaultorcurrent) - Headless-enabled bundles (entities) and View displays
For deployment and migration examples, see MIGRATION.md.
- Set “Drupal URL” so
drupal_urlis deterministic (don’t rely on Host headers). - Set
trusted_host_patternsinsettings.php. - If using
nextjs_first, setX-Proxy-Secretand keep it in env/settings.php(not config exports). - Rate limit
/jsonapi/resolve*and/jsonapi/*at the edge (Cloudflare/nginx) to prevent path brute-force load. - If using authenticated JSON:API, keep credentials server-side and never cache authenticated responses.
- For Next.js images, restrict remote domains (
DRUPAL_IMAGE_DOMAINin the starter).
- Entities: any canonical content entity route exposed by JSON:API (nodes, terms, media, users, and custom entities)
- Views: page displays with paths (requires
jsonapi_views) - Layout Builder: hybrid mode (keep bundles non-headless) or true headless via the optional add-on
jsonapi_frontend_layout(/jsonapi/layout/resolve). SeeMIGRATION.md.
- The resolver respects entity access; unpublished/restricted content resolves as “not found”.
- Resolver caching is only applied for anonymous requests; authenticated requests return
Cache-Control: no-store. - If you enable the routes feed (
/jsonapi/routes), keep the secret in build-only env vars and don’t expose it to browsers. - For config-managed sites, secrets are stored outside config exports (state) and can be overridden in
settings.php. - The endpoint lives under
/jsonapi/so it can share the same perimeter rules you apply to JSON:API. - If you run “frontend-first”, you can protect the Drupal origin with a shared secret header.
- If you want a fully hidden origin, you can also require the proxy secret for
/jsonapi/*(server-side fetching only). - For authenticated JSON:API, keep credentials server-side (Basic/OAuth/JWT). Cookie-based writes require Drupal CSRF tokens (
/session/token) and strict CORS.
- Migration guide:
MIGRATION.md - Changelog:
CHANGELOG.md - NPM client: https://www.npmjs.com/package/@codewheel/jsonapi-frontend-client
- Starter: https://github.com/code-wheel/jsonapi-frontend-next
- Menus (optional): https://www.drupal.org/project/jsonapi_frontend_menu
- Webforms (optional): https://www.drupal.org/project/jsonapi_frontend_webform
- Layout Builder (optional): https://www.drupal.org/project/jsonapi_frontend_layout