https://github.com/code-wheel/jsonapi-frontend-client
TypeScript client helpers for Drupal jsonapi_frontend
https://github.com/code-wheel/jsonapi-frontend-client
decoupled drupal headless jsonapi npm typescript
Last synced: about 2 months ago
JSON representation
TypeScript client helpers for Drupal jsonapi_frontend
- Host: GitHub
- URL: https://github.com/code-wheel/jsonapi-frontend-client
- Owner: code-wheel
- License: gpl-2.0
- Created: 2025-12-31T22:08:57.000Z (3 months ago)
- Default Branch: master
- Last Pushed: 2026-01-03T23:43:08.000Z (3 months ago)
- Last Synced: 2026-01-05T11:08:49.806Z (3 months ago)
- Topics: decoupled, drupal, headless, jsonapi, npm, typescript
- Language: TypeScript
- Homepage: https://www.drupal.org/project/jsonapi_frontend
- Size: 46.9 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# `@codewheel/jsonapi-frontend-client`
TypeScript client helpers for Drupal `drupal/jsonapi_frontend`.
This package is **optional**. You can always call `/jsonapi/resolve` directly with `fetch()`.
## Install
```bash
npm i @codewheel/jsonapi-frontend-client
```
## Usage
Set `DRUPAL_BASE_URL` (must be a full `http(s)://` URL), then:
```ts
import { 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)
}
```
## Layout Builder (optional)
If you install the `jsonapi_frontend_layout` add-on module, you can resolve a path and (when applicable) receive a normalized Layout Builder tree:
```ts
import { resolvePathWithLayout, fetchJsonApi } from "@codewheel/jsonapi-frontend-client"
const resolved = await resolvePathWithLayout("/about-us")
if (resolved.resolved && resolved.kind === "entity") {
const doc = await fetchJsonApi(resolved.jsonapi_url)
if (resolved.layout) {
console.log(resolved.layout.sections)
}
}
```
## Astro / Vite (`import.meta.env`)
```ts
import { resolvePath, fetchJsonApi } from "@codewheel/jsonapi-frontend-client"
const baseUrl = import.meta.env.DRUPAL_BASE_URL
const resolved = await resolvePath("/about-us", { baseUrl })
if (resolved.resolved && resolved.kind === "entity") {
const doc = await fetchJsonApi(resolved.jsonapi_url, { baseUrl })
}
```
## Authentication (optional)
Keep credentials server-side. Pass headers via `options.headers`:
```ts
import { resolvePath } from "@codewheel/jsonapi-frontend-client"
const baseUrl = process.env.DRUPAL_BASE_URL!
const auth = "Basic " + Buffer.from(`${process.env.DRUPAL_BASIC_USERNAME}:${process.env.DRUPAL_BASIC_PASSWORD}`).toString("base64")
await resolvePath("/about-us", {
baseUrl,
headers: { Authorization: auth },
})
```
```ts
import { resolvePath } from "@codewheel/jsonapi-frontend-client"
await resolvePath("/about-us", {
headers: { Authorization: `Bearer ${process.env.DRUPAL_JWT_TOKEN}` },
})
```
### Caching note (Next.js / SSR)
If you pass `Authorization` (or `Cookie`) headers, this client defaults to `cache: "no-store"` unless you explicitly set `options.init.cache`.
## Static builds (SSG) routes feed (optional)
If you enable the secret-protected routes feed in Drupal (`/jsonapi/routes`), you can fetch a complete build-time list of headless paths by following `links.next`:
```ts
import { collectRoutes } from "@codewheel/jsonapi-frontend-client"
const baseUrl = process.env.DRUPAL_BASE_URL!
const secret = process.env.ROUTES_FEED_SECRET!
const routes = await collectRoutes({ baseUrl, secret })
const paths = routes.map((r) => r.path)
```
Keep `ROUTES_FEED_SECRET` server-side only (build environment variables). Do not expose it to browsers.
## Menus (optional)
If you install the `jsonapi_frontend_menu` add-on module, you can fetch a ready-to-render tree:
```ts
import { fetchMenu } from "@codewheel/jsonapi-frontend-client"
const menu = await fetchMenu("main", { path: "/about-us" })
console.log(menu.data)
```
## Query building (optional)
This client doesn’t require a query builder, but `drupal-jsonapi-params` works well:
```ts
import { DrupalJsonApiParams } from "drupal-jsonapi-params"
import { fetchJsonApi } from "@codewheel/jsonapi-frontend-client"
const baseUrl = process.env.DRUPAL_BASE_URL!
const params = new DrupalJsonApiParams()
.addFilter("status", "1")
.addFields("node--article", ["title", "path", "body"])
const url = `/jsonapi/node/article?${params.getQueryString()}`
await fetchJsonApi(url, { baseUrl })
```
## URL safety (recommended)
By default, `fetchJsonApi()` and `fetchView()` refuse to fetch absolute URLs on a different origin than your `DRUPAL_BASE_URL` (to avoid accidental SSRF in server environments).
If you intentionally need to fetch a cross-origin absolute URL, pass `allowExternalUrls: true`:
```ts
import { fetchJsonApi } from "@codewheel/jsonapi-frontend-client"
await fetchJsonApi("https://cms.example.com/jsonapi/node/page/...", {
allowExternalUrls: true,
})
```