Creating a Simple Server with Next.js

It can take a long time to get a full-stack React and Node.js app off the ground. Fortunately, with the addition of API Routes, Next.js offers a way to do that in just minutes.

Next & File System Routing

Next.js is a powerful, batteries-included React “framework.” It is responsible for page routing, code splitting, server-side rendering, and more. I started using it recently and have come to appreciate it tremendously. It takes a lot of the pain (i.e. Webpack) out of the development experience of working on a React app (especially when TypeScript is involved). The developer can focus on building the app, rather than wrangling configuration files.

One of the things that I appreciate about Next is the file system routing. All of the React pages are stored in the pages directory, and the file-path determines the URL. So, if you have a file stored in pages/path/to/file.tsx, that will be served when you visit http://your-website.com/path/to/file. It’s super-fast to get a React app up and running with Next, and this is one of the features that makes that possible.

The magic of the file system page routing also enables the topic of this post: API routes.

API routes are available in Next.js 9. With this addition, you can now run, build, and deploy your front end and back end within the same ecosystem. You no longer need a separate server or API, as the API routes can take care of it all.

Creating a Simple Server with Next.js

So, let’s dive in to a quick example to set up a simple page with data coming from a Next API route. If you want to add the API routes to an existing Next app, then skip to the “Adding an API Route” section. Otherwise, we’ll start from scratch.

1. Create a Next App

First things first: Let’s create a Next app:
yarn create next-app next-api-routes or npx create-next-app next-api-routes

This should spit out some logs indicating that dependencies were installed.

cd into that directory, and run yarn dev. You should see that a sample application is up and running.

Optionally, rename the file from pages/index.js to pages/index.tsx if you would like to start using TypeScript. You will also need to run yarn add --dev typescript @types/react @types/node to install the additional dependencies. Next has out-of-the box support for TypeScript, so no additional setup is required. Awesome!

Now, lets’s get rid of the boilerplate code from our pages/index.tsx component and start fresh with the following:

 
// pages/index.tsx
import React, { useState } from "react";

const Home = () => {
  const [name, setName] = useState("World");
  return 
Hello, {name}
; }; export default Home;

You should now see a simple page with the text, “Hello, World.” Let’s update it to get the name from our API (which we have yet to build).

To fetch data, we could use the Fetch API, but because Next is server-rendered, we may not have access to it. We could use another library such as node-fetch to allow us to run the request from Node. This could work, but it can get confusing to decide whether we should use window.fetch or node-fetch with Next.

For this reason, many people tend to use another request library such as Axios or isomorphic-fetch that can handle browser and Node requests without any configuration. In this example, I’m going to use Axios.

Run yarn add axios to install Axios.

Update the pages/index.tsx file:

 
// pages/index.tsx
import React, { useState, useEffect } from "react";
import Axios from "axios";

const Home = () => {
  const [loading, setLoading] = useState(true);
  const [name, setName] = useState("World");

  useEffect(() => {
    const fetchData = async () => {
      const response = await Axios.get("http://localhost:3000/api/hello")

      if (response.status === 200 && response) {
        setLoading(false);
        setName(response.data);
      }
    };
    fetchData();
  }, []);

  if (loading) {
    return 
Loading...
; } return
Hello, {name}
; }; export default Home;

We added some code to handle the loading state, but we should ideally handle error cases. Eventually, we should also take the API URL out of a hard-coded string in this component. For now though, let’s not worry about those issues.

Now that the front end is set up to handle talking to an API, let’s add the server.

2. Adding an API Route

Just like the page routing, the API routing is is based on the filesystem. The files under the pages/api path are set up to handle HTTP requests.

So, let’s create a new API route!

mkdir pages/api
touch pages/api/hello.ts

Note that the file pages/api/hello.ts matches the URL that we created in our pages/index.tsx component.

An API route needs to export a default function that takes a next request and next response object, like so:

 
// pages/api/hello.ts
import { NextApiRequest, NextApiResponse } from "next";

export default (request: NextApiRequest, response: NextApiResponse) => {
};

This might look familiar if you have used Express or the Node HTTP server. The request is an extension of the http.IncomingMessage, and the response is an extension of the http.ServerResponse.

The request object has properties available such as request.body, request.query, and request.cookies.

So, to send back data, we can simply send:

 
// pages/api/hello.ts
import { NextApiRequest, NextApiResponse } from "next";

export default (request: NextApiRequest, response: NextApiResponse) => {
  response.status(200).end("API");
};

And that’s it! If you reload the page, you should see the text “Hello, API” appear. From this point on, you can write any Node code that your heart desires.

Wrapping Up

As you can see, adding an API route to a Next.js app is quite simple. This allows us to create a full-functioned React front end and Node API with very little code or configuration. The development is smooth, and the building and deployment are a breeze thanks to the Next tooling. I’m excited about using Next, and I would highly encourage giving it a chance.