Building Pages

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


In Next.js, you fetch server-side data in either getStaticProps or getServerSideProps. Data is then fed to your pages for pre-rendering.

The DrupalClient 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:

pages/about.tsx

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

Dynamic pages

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

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

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

To build static pages, there are two functions we need to implement:

  1. getStaticPaths: to tell Next.js all the routes that we want to be rendered.
  2. getStaticProps: to fetch data for pages.

pages/[...slug].tsx

export default function Page({ node }) {
return (
<article>
<h1>{node.title}</h1>
// ...
</article>
)
}
export async function getStaticPaths(context) {
// Build paths for all `node--page`.
return {
paths: await drupal.getStaticPathsFromContext("node--page", context),
fallback: false,
}
}
export async function getStaticProps(context) {
// Fetch the node based on the context.
// next-drupal automatically handles the slug value.
const node = await drupal.getResourceFromContext("node--page", context)
return {
props: {
node,
},
}
}

Advanced Example

In the example above, we used pages/[...slug].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 translatePathFromContext which returns info about the resource type based on slug value in context.

export async function getStaticProps(context) {
const path = await drupal.translatePathFromContext(context)
// Get the resource type.
const type = path.jsonapi.resourceName
if (type === "node--article") {
// Build custom JSON:API query for article.
}
if (type === "node--page") {
// Build custom JSON:API query for page.
}
}

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

pages/[...slug].tsx

import { DrupalJsonApiParams } from "drupal-jsonapi-params"
export default function Page({ node }) {
if (node.type === "node--page") {
return <PageComponent />
}
if (node.type === "node--article") {
return <ArticleComponent />
}
return null
}
export async function getStaticPaths(context) {
// Build paths for all `node--page` and `node--article`.
return {
paths: await drupal.getStaticPathsFromContext(
["node--page", "node--article"],
context
),
fallback: false,
}
}
export async function getStaticProps(context) {
const path = await drupal.translatePathFromContext(context)
// 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.getResourceFromContext(type, context, {
params: params.getQueryObject(),
})
return {
props: {
node,
},
}
}

Reference

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