Building Pages

How to build pages using JSON:API resources from Drupal.


In Next.js V14, data fetching has evolved significantly from previous versions. Instead of using getStaticProps and getServerSideProps you now use the native fetch function enhanced by Next.js to handle server-side data fetching.

The NextDrupal client provides several functions to help you query JSON:API resources from Drupal.


Basic Example

Here's an example which uses getResource to fetch a page node by ID:

const node = await drupal.getResource(
"node--page",
"07464e9f-9221-4a4f-b7f2-01389408e6c8"
)

A full page would look like this:

app/about/page.tsx

// page will be generated at build time
export default function AboutPage() {
// Fetch the node from Drupal.
const node = await drupal.getResource(
"node--page",
"07464e9f-9221-4a4f-b7f2-01389408e6c8"
)
return (
<article>
<h1>{node.title}</h1>
// ...
</article>
)
}

Dynamic pages

You can use Next.js dynamic routes to build static pages for Drupal entity types.

Start by creating a page at /app/[...slug]/page.tsx, where [...slug] maps to the path alias for an entity type (or content type) in Drupal.

This means /app/[...slug]/page.tsx will handle all pages with the following aliases: /about, /team, /another/path ...etc.

To build static pages, there is a built-in function we need to use:

generateStaticParams: to tell Next.js all the routes that we want to have pre-rendered at build time.

app/[...slug]/page.tsx

export async function generateStaticParams() {
// Build paths for all `node--page`.
const resources = await drupal.getResourceCollectionPathSegments(
"node--page"
);
return resources.map((resource) => slug: resource.segments);
}
export default function Page({ params }) {
const {slug} = params;
// Construct drupal path based on params
const drupalPath = drupal.constructPathFromSegment(slug)
// Fetch the node based on drupal path.
const node = drupal.getResourceByPath(drupalPath)
return (
<article>
<h1>{node.title}</h1>
// ...
</article>
)
}

Advanced Example

In the example above, we used app/[...slug]/page.tsx to build static pages for node--page.

We can go a step further and handle all node types (or any entity types) in one page.

To do that, we're going to use translatePath which returns info about the resource type based on slug value in params.

Let's update app/[...slug]/page.tsx to handle both node--page and node--article.

app/[...slug]/page.tsx

import { DrupalJsonApiParams } from "drupal-jsonapi-params"
export async function generateStaticParams() {
// Build paths for all `node--page` and `node--article`.
const resources = await drupal.getResourceCollectionPathSegments(
["node--page", "node--article"]
);
return resources.map((resource) => slug: resource.segments);
}
export default function Page({ params }) {
const {slug} = params;
const path = drupal.translatePath(slug)
// Get the resource type.
const type = path.jsonapi.resourceName
const params = new DrupalJsonApiParams()
// Fetch the title, path and body field for pages.
if (type === "node--page") {
params.addFields("node--page", ["title", "path", "body"])
}
// Fetch additional fields for articles.
if (type === "node--article") {
params.addFields("node--article", ["title", "path", "body", "uid"])
}
const node = await drupal.getResource(path, path.entity.uuid {
params: params.getQueryObject(),
})
// Render different Components based on Node type.
if (node.type === "node--page") {
return <PageComponent node={node}/>
}
if (node.type === "node--article") {
return <ArticleComponent node={node}/>
}
return null
}

Reference

See the fetching JSON:API resources section for more examples of fetching resources and collection of resources.

Pages Router

TODO