Define and Use Next.js API Routes to Make Server Side Requests

Lazar Nikolov
InstructorLazar Nikolov

Share this video with your friends

Send Tweet
Published 2 months ago
Updated 2 months ago

Next.js is built on top of Node.js which means that you can define functions that will only run on the server. These functions are called API routes.

These API routes allow you to interact with 3rd party services, connect to the database, or use environment secrets without exposing any of that to the client. In short, they let you build out an API all inside of Next.js.

In this lesson, you’ll see how to fetch user data by id and return that data from an API route. You’ll learn about handling requests sent to the API route and what type of responses to send back to the client.

Lazar Nikolov: [0:00] We've reached the last Next.js feature for this course, and that's the API routes. Since Next.js is built on top of Node.js, it also allows us to define our own API routes.

[0:13] The API routes are functions that are part of the server, but instead of rendering HTML, they're returning JSON data. Any file inside of the pages/API directory is mapped to /API, and it will be treated as an API endpoint instead of a page.

[0:28] These functions are server sites and will not be bundled with our client-side code. That means we can safely open database connections and use secret environment variables.

[0:38] For new projects, we can build our entire API with API routes. If we already have an existing API, we don't need to forward our API calls through an API route. We could also use API calls, if we want to mask our API or an external service.

[0:55] Before we dive in, let's check out the project. Let's open exercise number 14, and open index.tsx file. Let's also run it. We'll do npm run dev, and hit refresh.

[1:10] We can see that the starting app has two sections. The first one is a list of demo users, and the second one displays the details for every selected user.

[1:21] If we try clicking on the users, nothing happens. We're going to implement an API route that returns the selected user details. We can see that we have a fetchUser method that accepts the user ID and sends an HTTP request to an endpoint which we'll need to define.

[1:44] Let's begin. Inside of the Pages directory, let's create a new folder and call it API. Then inside of the API folder, we'll create a new folder called Users. Inside of the Users folder, we will create a new file called userID.ts. We will wrap the user ID with brackets, because we need to get the user ID.

[2:08] This is very similar to how we created dynamic routes. To build our API handler, we need to create a new method called handler, which is an async method and do export default handler. The name doesn't really matter.

[2:27] Because we're using TypeScript, we can also import the type NextApiHandler from the Next package, and set that type to the handler method, so NextApiHandler.

[2:42] Every API route accepts two parameters, that is the request and response. The request is an instance of the http.IncomingMessage object plus some pre-built middlewares. The response is an instance of the http.ServerResponse object plus some helper functions.

[3:03] Let's see what's inside of the requests. We can see that we have a body property, which contains the body of the HTTP request that the user has sent, we also have the cookies object that could contain the authorization cookie of the user sending the request.

[3:20] We can see that we also have the method property, which describes the type of the HTTP method that this API handler will receive, so it can be GET, DELETE, PUT, POST, etc. We have the query property that contains all of the query values from the URL, which in this case, we have the user ID.

[3:41] Let's start. Because this method is going to be a GET only method, we can provide an IF condition based on the request.method. If the method is a GET method, then we will handle it. Otherwise, we need to return an error that says the method is not allowed.

[4:01] We can do return and then use the response object to send a status of 405, and return a JSON with an error property of method not allowed.

[4:16] Now, this means if someone sends an API request to our handler which is not of type GET, they will receive a 405 error, which says method not allowed. Nice.

[4:27] Now, let's get inside of the IF condition. First, we can obtain the user ID by the request.query that we just mentioned. So userID = request.query.userID, and we will cast it as a string.

[4:43] Then we need to get the user from all of the users. If we open up the project, we can see that we have a data directory and the users.ts. This file contains the list of demo users.

[4:58] We can go back to our API route and import the users. We will do import users from, and then we will jump three times data/users. This makes it simpler, so we don't open any database connections.

[5:14] Now, let's obtain the user from the users, so users.find. We will obtain the ID of the users, and we will return the user whose ID is the same as the same as the provided one. Because the user ID from the query is a string, we need to parse it as an integer.

[5:36] That's how we can obtain the user. If the user does not exist, we need to return result.status of 404, that is the not found status, and then we can return a JSON with the error, "User not found."

[5:52] Otherwise, if the user exists, we need to return result.status of 200, which is the HTTP code for OK, then .JSON and then we'll just return the user. That's it. Our API route is now completed. In order to use it, let's go back to the index page and set the endpoint.

[6:15] The endpoint will be a string template of /API/users and then /the user ID. Now, let's save this and refresh. If we click on the users, we can see that their details are changing. If we open up the inspect element and go to the network tab, we can see that we are sending HTTP requests to our route every time we click on a user.

[6:46] Here's the first one, returns a user and the rest of them. If you go to the headers tab, we can see that our API handler lives in the /API/users. In this case, it's user with the ID of six. If we try to change the ID, and let's use an ID that probably does not exist.

[7:05] Let's see what happens. It says the user is not found or the status code is 404. The preview contains an error saying that the user is not found. This is this case within our API handler.

[7:24] If we change the fetch from GET to a different method, so we can override the method property and set it to POST, and try clicking on a user, we can see that the status code is 405 or the method not allowed, because we are making a post request to our API handler.

[7:49] The preview contains an error saying method not allowed. In our case, this is the line that returns the error. That's how we can build API handlers. Let's recap. Since Next.js is built on top of Node.js, it allows us to define our own API routes. The API routes lived inside of the API folder inside of the page's directory.

[8:15] Everything that lives inside of the API folder is mapped to /API. Those files will not be treated as a page even though they are in the page's directory, but they will be treated as an API endpoint. The API routes are a server-side and will not be bundled with our client-side code.

[8:31] That means we can safely open database connections and use secret environment variables. To make an API route, we needed to export a default async function that accepts the request and the response into its argument and optionally, it can use the NextApiHandler type.

[8:48] The request object contains the method, body, and query properties that we can use to handle the request. Using the request.method, we can check if the method's type is GET, POST, PUT, DELETE and act accordingly.

[9:03] We can use the query property to obtain any dynamic parts, which in this case is the user ID, and we can use the response object to send down the response back to the browser. In this case, we can either return a result, or we can return a suitable error based on the conditions.