DEV Community

Cover image for Generate Dynamic JSON Pages with Next.js
Sean C Davis for Grouparoo

Posted on • Originally published at grouparoo.com

Generate Dynamic JSON Pages with Next.js

Next.js is a super powerful tool for building scalable websites and web applications. Building dynamic web pages is no big thing with Next.

I had a scenario pop up in which I wanted to generate and deliver JSON pages. I wanted to retrieve the data from elsewhere and then output it to a file that didn't have to change between builds.

Limitations of Pages in Next.js

Part of the reason Next is equal parts powerful and easy to use is a result of the opinions it brings along. One such opinion is the way in which pages are delivered.

While there are options to fetch data prior to rendering a page, pages are rendered as React components. And they are wrapped in application-level components.

That means there isn't an easy way for me to follow the Next.js pages pattern to generate statically dynamic JSON pages.

Fortunately, I found two ways in which I could still accomplish what I wanted in two other ways.

The Setup

Before we walk through these two examples, I'm assuming you have a Next.js project ready to go. If you don't you can use create-next-app to start with the default template.

$ npx create-next-app
Enter fullscreen mode Exit fullscreen mode

We're going to install a single dependency for this example, axios:

$ npm install axios
Enter fullscreen mode Exit fullscreen mode

Once it seems you're ready to go, boot that development server. With the default template, that command is:

$ npm run dev
Enter fullscreen mode Exit fullscreen mode

And the server runs at localhost:3000 in your browser.

If you had an existing Next project, you may have a different command to start the dev server and a different port on which the front end runs.

Method #1: API Routes

Now that you're up and running, let's look at our first option for generating JSON pages: API routes.

Okay, I lied. A little. Pages in next don't have to be React components. Next also supports what they call API routes. These are methods that run on the server side and return data back to the user. That feels like a really good use case for our scenario.

Let's pretend that we want to return a single random dad joke.

Starting Simple

As a quick introduction to API routes, let's first create a page at pages/api/joke.js with the following content:

// pages/api/joke.js

export default (req, res) => {
  res.status(200).json({ hello: "World" });
};
Enter fullscreen mode Exit fullscreen mode

Now visit http://localhost:3000/api/joke in your browser, or make a GET request to that same URL through an API client. You'll see on screen (or in your client) the object we sent:

{ "hello": "world" }
Enter fullscreen mode Exit fullscreen mode

Great!

Making it Dynamic

Now let's make it dynamic by adding axios and querying the icanhazdadjoke.com API:

// pages/api/joke.js

import axios from "axios";

export default async (req, res) => {
  const { data } = await axios.get("https://icanhazdadjoke.com/", {
    headers: { Accept: "application/json" },
  });

  res.status(200).json(data);
};
Enter fullscreen mode Exit fullscreen mode

There's not much to that, really. We're asking the icanhazdadjoke.com API for a response and passing that response on to the user.

Now refresh your browser or make a request through your API client again and you'll be sent something classically witty like this:

{
  "id": "xXg3LZLZDd",
  "joke": "*Reversing the car* \"Ah, this takes me back\"",
  "status": 200
}
Enter fullscreen mode Exit fullscreen mode

Note that if you were going to take this into production, you'd want to put some checks in place to guard against the icanhazdadjoke.com API being down or giving you something you didn't expect.

Method #2: Static File

The first method is powerful and all, but it's also forcing you into a solution in which you have to run that method (i.e. do some work, like hit another API) every time you want the data in this file.

Recall in the intro that I mentioned a nuance of not needing the file to change in between builds. Thus, the JSON file itself should be generated dynamically, but could be delivered statically. (This has all the makings of a static API.)

While we know we can't make pages as static JSON files, we could generate a static JSON file prior to building the site and serve it as a static asset.

Generate Script

To do that, let's put together a little script at scripts/getJoke.js which retrieves the dad joke and then writes it to a file at public/joke.json.

Note: We're putting it in the public directory because these files get copied over directly. A file at public/joke.json would be available at /joke.json on our website.

// scripts/getJoke.js

const path = require("path");
const fs = require("fs");
const axios = require("axios");

const filePath = path.join(__dirname, "../public/joke.json");

const main = async () => {
  const { data } = await axios.get("https://icanhazdadjoke.com/", {
    headers: { Accept: "application/json" },
  });

  fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
};

main().then(() => console.log("Done."));
Enter fullscreen mode Exit fullscreen mode

Notice this is very similar to our API function. But instead of returning the response, we write it to file.

To see it in action, you can run the script like this from the root of your project:

$ node ./scripts/getJoke
Enter fullscreen mode Exit fullscreen mode

Check your public directory for a joke.json file.

{
  "id": "xXg3LZLZDd",
  "joke": "*Reversing the car* \"Ah, this takes me back\"",
  "status": 200
}
Enter fullscreen mode Exit fullscreen mode

You can verify that it will be available on your website by visiting localhost:3000/joke.

Automate It!

To automate this process, we can add a pre script to hook into the appropriate script in our package.json file.

For example, let's say we want this to run before we run the npm run dev script. To do that, add a predev script to your package.json file:

// package.json

{
  // ...
  "scripts": {
    "predev": "node ./scripts/getJoke",
    "dev": "next dev"
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, whenever you run npm run dev, your getJoke script will run, producing a new static file.

Try it out. Stop your server (if it's still running) and start it back up. Then visit localhost:3000/joke to see new content!


There are two methods for taking dynamic data and rendering it as JSON in your Next.js application. One updates itself on every request, the other on every build. Choose the best path for you and keep building cool things!

Top comments (2)

Collapse
 
sergeyre profile image
SergeyRe

you can use page props to serve as static json api
its available under the path ./_next/data/build_id/page_slug.json
its good case for custom build id
nextjs.org/docs/api-reference/next...
example for sure
todayandnow.ru/_next/data/my-build...
for this page
todayandnow.ru/chem-zanyat-detei-n...

Collapse
 
seancdavis profile image
Sean C Davis

That's a creative approach!