Next-Drupal 1.3
April 19, 2022 - @shadcn
Since releasing next-drupal 1.0
last December, we have seen incredible adoption. Our community has grown beyond expectations. We are now approaching 1000+ downloads per week.
Today we're excited to release next-drupal 1.3
, one of our most important releases.
Next-Drupal 1.3 ships a powerful and flexible JSON:API client for fetching data from Drupal.
It is a replacement for functional helpers such as getResource
and getResourceCollection
and provides tons of customizations.
The DrupalClient
is an optional feature. You can safely upgrade your site to next-drupal 1.3.0
without any breaking changes.
Features
- Customizable JSON:API client for data fetching.
- Helpers to fetching resources, menus, views and search indices.
- Support for custom auth -
Bearer
,Basic
or bring your own. - Support for custom serializer.
- Support for custom fetcher.
- Support for cached resources - memory cache, redis...etc.
- Improved error messages
DrupalClient
The DrupalClient
is available in next-drupal ^1.3.0
as experimental.
lib/drupal.ts
import { DrupalClient } from "next-drupal"
const drupal = new DrupalClient("https://example.com")
// Fetch articles.const articles = await drupal.getResourceCollection("node--article")
Data Fetching
Every data fetching helper has been upgraded and made more flexible with options for authentication, localization and caching.
import { drupal } from "lib/drupal"
// Fetch articles.const articles = await drupal.getResourceCollection("node--article")
// Fetch articles with translation.const articles = await drupal.getResourceCollectionFromContext( "node--article", context)
// Get static paths for resources.const paths = await drupal.getStaticPathsFromContext( ["node--article", "node--page"], context)
// Make an auth request to fetch a block.const menu = await drupal.getResource( "block_content--basic", "42487873-3aad-44ab-8dd6-c2fb0d82bb8f", { withAuth: true, })
// Fetch a menu and cache the response during build.const menu = await drupal.getMenu("main", { withCache: process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD, cacheKey: `menu:main`,})
Auth
In addition to Bearer tokens (via Simple OAuth), you can now provide own custom authentication implementation for fetching Drupal data.
Bearer
To configure authentication, provide a client_id
and client_secret
as options.
lib/drupal.ts
export const drupal = new DrupalClient( process.env.NEXT_PUBLIC_DRUPAL_BASE_URL, { auth: { clientId: process.env.DRUPAL_CLIENT_ID, clientSecret: process.env.DRUPAL_CLIENT_SECRET, }, })
DrupalClient
will fetch Bearer token and handle expiration for you.
Basic
You can also use the basic authorization header as follows:
You need to enable the basic_auth
module on Drupal.
lib/drupal.ts
export const drupal = new DrupalClient( process.env.NEXT_PUBLIC_DRUPAL_BASE_URL, { auth: () => "Basic " + Buffer.from( `${process.env.BASIC_AUTH_USERNAME}:${process.env.BASIC_AUTH_PASSWORD}` ).toString("base64"), })
Callback
You can also provide a custom callback for authentication. The callback must return an Authorization
compatible header.
lib/drupal.ts
export const drupal = new DrupalClient( process.env.NEXT_PUBLIC_DRUPAL_BASE_URL, { auth: () => { // Authenticate and return headers. }, })
Serializer
The DrupalClient
uses jsona as the default serializer for serializing and deserializing JSON:API data.
You can provide your own using the serializer
option.
lib/drupal.ts
import { Deserializer } from "jsonapi-serializer"
const customSerializer = new Deserializer({ keyForAttribute: "camelCase",})
export const drupal = new DrupalClient( process.env.NEXT_PUBLIC_DRUPAL_BASE_URL, { serializer: customSerializer, })
Fetcher
You can now provide your own fetcher using the fetcher
option. This replaces Next.js' polyfilled fetch
for JSON:API calls.
lib/drupal.ts
import { DrupalClient } from "next-drupal"import crossFetch from "cross-fetch"
const fetcher = (url, options) => { const { withAuth, ...opts } = options
if (withAuth) { // Make additional requests to fetch a bearer token // Or any other Authorization headers. }
return crossFetch(url, { ...opts, // Pass in additional options. Example: agent. })}
export const drupal = new DrupalClient( process.env.NEXT_PUBLIC_DRUPAL_BASE_URL, { fetcher, })
Caching
The DrupalClient
has support for caching resources. You can provide your own cache implementation using the cache
option.
Here's an example on how you can use Redis to cache resources.
lib/drupal.ts
import { DrupalClient, DataCache } from "next-drupal"import Redis from "ioredis"
const redis = new Redis(process.env.REDIS_URL)
// Create a custom cache.export const redisCache: DataCache = { async set(key, value) { return await redis.set(key, value) },
async get(key) { return await redis.get(key) },}
export const drupal = new DrupalClient( process.env.NEXT_PUBLIC_DRUPAL_BASE_URL, { cache: redisCache, })
Now when you make a getResource
or getMenu
call, you can tell the client to cache and re-use responses.
lib/get-menu.ts
import { PHASE_PRODUCTION_BUILD } from "next/constants"
const menu = await drupal.getMenu("main", { withCache: process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD, cacheKey: `menu:main`,})
Error Messages
We have improved the error messages from the client with support for formatted JSON:API errors.
Upgrading
You can try the new DrupalClient
today by following our upgrade guide here.