James Calmus
18 Mar 2021
•
6 min read
Over the course of my articles on Next.js, we’ve explored some of the front-end and more generic aspects of the popular framework, from setting up and using a utility-first CSS framework to getting started with testing your project.
In this article, we’re going to be focusing on the backend as we discover Next.js’s API routes.
At its heart, Next.js is a route-based framework for React; that’s one of the reasons it was built and what has made it so popular, because, instead of programmatically declaring the structure of your app as you do with vanilla React, you use your file structure to do it instead.
This feature can be incredibly powerful when used effectively, especially when it comes to dynamic routing and the handling of complex queries.
Building on this, and Next.js's support for server-side processing, version 9 introduced the concept of API routes. This combines Express-like RESTful endpoint creation with directory-based routing. Adding a JavaScript file into an api
directory in pages
creates an endpoint you can access in the browser that runs in a Node.js environment.
These routes are so simple to set up, and give you the ability to craft your own API, separate from your front-end but in the same repository.
The result is one of Next.js’s most powerful, and easy-to-use, features.
As I said, setting up these API routes is an incredibly quick affair. If you’ve created an Express endpoint before, you may also recognise some of the functions we use.
Let’s start where we left off our last project. If you need the code again, you can grab it from here - just make sure you open your terminal and install the repository's packages by running the command below:
$ yarn install
If you look at the project directory structure, you’ll see a pages
folder. We know that Next.js uses the files in this folder to create our app’s route structure – i.e., the URLs that make up our app. Inside the pages
folder, we have two files, our _app
definition file and our homepage, index.js
.
We also have a folder inside pages
called api
, and inside that folder, there is a single file called hello.js
. Opening the file should show you an endpoint definition that looks like this:
// hello.js
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default (req, res) => {
res.statusCode = 200
res.json({ name: ‘John Doe’ })
}
Just as with its parent folder and creating pages for our app, every file inside api
is treated as an endpoint and immediately accessible. That means if we run our app by running the following command in our terminal:
$ yarn dev
and head to http://localhost:3000/api/hello
, we should see the result of our call, which looks something like this:
{ "name": "John Doe" }
So now we know our API route works, let’s go back to the endpoint’s definition in hello.js
to see how it works.
Inside hello.js
we can see a single, default exported function that takes two parameters, req
and res
, short for "request" and "response", respectively.
The default function is invoked when we visit http://localhost:3000/api/hello
, and the req
parameter is populated by the details of our request, such as headers, the URL we were trying to access and any query parameters contained in that URL. This is going to be useful to us later.
The res
parameter allows us to access a few, Express-like functions to shape the response from our exported function. In hello.js
, you can see our example API uses two of these functions, statusCode
– which is fairly self-explanatory and sets the response's status code - and json
- which returns a json object payload, in this case a name
field set to John Doe
.
If you want to see the status code function in action, head back to http://localhost:3000/api/hello
in your browser, open the developer tools tab and click on Network
. If you're not sure how to open your dev tools tab, take a look at this guide.
If you've never used the Network tool before, it's a great way of learning all about the requests your browser makes to display its content. Because we opened it after the network request for our API route had completed, you should see an empty list. Now refresh your browser tab.
You may see a number of requests occur, some of which could be related to any browser extensions you have installed. In amongst those requests you should see one with the name hello
, which is our API route, either with a status of 200
or 304
(meaning a cached version has been returned). If you see 304
, hard refresh the tab by holding the shift
key while refreshing your tab to see a status code of 200
.
To show how easy it is to change our API route's status code, let's head back to hello.js
in the code editor.
Change line 4, to read the following:
// hello.js
res.statusCode = 404
Now head back to your browser and hard refresh the tab. In your network request list, you should see 404
listed in the Status
column alongside the request titled hello
. Congratulations, you've just successfully used a Next.js response object to alter your API route's status code!
Revert line 4 so our API route is returning a 200
status code again:
// hello.js
res.statusCode = 200
Now let's change the data that our API route sends back.
In hello.js
, we use the json
function to return "John Doe". Update that string to contain your own name. In my case, when I save the file and head back to the browser tab to refresh it, the response now shows the following:
{"name":"James Calmus"}
We've now defined an endpoint that returns a static response using Next.js.
Some API routes might not take any inputs, such as the one we're currently working with. No matter when, where or with what extra parameters you call the hello
API route, it will always return the same response.
There are many situations, however, where you'd like to specify some data for the API to process. For example, if you create an API route that subscribes a user to a newsletter, you'll need the user's email address to subscribe them.
The simplest way to send this data is by using a query parameter, a set of terms that follow a ?
in a URL. Next.js has built-in support for query parameters, and it's incredibly easy to start consuming them.
Let's update our API to consume some query parameters that build our name.
In your browser address bar, type the following URL: http://localhost:3000/api/hello?fname=foo&lname=bar
. When you press enter
, the API still returns your name:
{"name":"James Calmus"}
What we want to do is to pull in the value of the variables we put into the address bar: fname
and lname
, and return them together as the value of name
, so it reads "foo bar". To do that, we need to access that url data, which as I explained before can be accessed from the req
object. Query parameters are accessible as an object via req.query
.
Above line 4, add the following code:
// hello.js
const {
fname,
lname,
} = req.query;
We want to output these values to prove our API route is correctly consuming the inputs. On line 9, we need to replace our hard-coded name output with fname
and lname
which we can do by using a string literal:
// hello.js
res.json({ name: `${fname} ${lname}` })
If we return to the browser and refresh the tab, you should now see the following output:
{"name":"foo bar"}
This proves our API route is consuming the data we're passing through to it via query strings!
Next.js API routes are extremely useful and flexible. We've only scratched the surface of what's possible but with this knowledge, I hope you'll be able to explore API routes in more depth and start creating some really interesting endpoints.
If you'd like the code we produced in this short guide, you can find a repository here.
And if you'd like to learn more about testing Next.js API routes, I recommend Sean Connelly's blog post, Unit Testing Next.JS API Routes.
James Calmus
See other articles by James
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!