In this tutorial, you’ll learn how to build APIs using Next.js 14. The latest version of Next.js lets you create APIs with the App Router.
Let’s start by creating our Next.js 14 project. As a prerequisite, you’ll be required to have Node.js 18.17 or later to work with Next.js 14. You can check the Node.js version currently installed on your system. For that, open your command prompt and type in the following command,
node --version
which will output something like,
v20.10.0
If you already have the required version installed, you are good to go. Otherwise, install the latest version of Node.js.
Once you have the required Node.js installed, you can start by creating a new Next.js project using `create-next-app`.
npx create-next-app@latest
The above command will prompt for a couple of questions related to the project creation,
√ What is your project named? ... next-14-api
√ Would you like to use TypeScript? ...Yes
√ Would you like to use ESLint? ... No
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ...Yes
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@/*)? ... No
Enter the responses as shown above, and once done, you will have a boilerplate Next.js project ready to run.
Navigate to the project directory and run the project.
cd next-14-api
npm run dev
Open your browser to http://localhost:3000 to see the default project running.
Building API Using Next.js: Project Structure
You have the ‘ src ‘ folder inside the project folder, `next-14-api`. All the project source code resides inside the `src` folder. Inside the `src` folder, create a folder called `api`, which will serve as the main folder for our Next.js APIs.
Once you have the `api` folder, create a folder called `users`, and inside `users` create a file called `route.ts`. Every API endpoint will have a file called `route.ts`.
In our case, since `route.ts` is inside the `api/users/` folder, the API endpoint will be `/api/users`.
GET API Endpoint
To begin with, let’s create an API endpoint inside the `route.ts` file. Start by defining a function for a GET request as shown.
typescript
const GET = () => {
return Response.json({"status":200, "message":"SUCCESS"})
}
export {GET}
As shown above, we return a JSON response for the API endpoint’s GET request.
To test the GET request API endpoint, you can restart the application. Once the application is up and running, try accessing the endpoint at http://localhost:3000/api/users to see the response.
{"status":200,"message":"SUCCESS"}
In addition to what we defined above, let’s make it more realistic by adding an API call inside the GET method. For that, you need to mark the method as `async` since we’ll be using `await` to fetch the data from the API.
typescript
const GET = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const responseData = await response.json();
return Response.json({"status":200, "data": responseData})
}
export {GET}
In the above code, we are making an API request to an external API endpoint and then returning the received data as the response from our `/api/users` endpoint.
Save the above changes and try making a GET request to http://localhost:3000/api/users, and you’ll be able to see a JSON response with data from the external API endpoint.
Now, let’s have a look at how you can read the query parameters from the API endpoint. Here is how you can pass a query parameter to the endpoint:http://localhost:3000/api/users?id=1. To read the query parameter passed to the endpoint, add a `request` parameter to the GET method.
const GET = async (request:any) => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const responseData = await response.json();
return Response.json({"status":200, "data": responseData})
}
Next, let’s create a URL using the `url` from `request`.
typescript
const { searchParams } = new URL(request.url);
Once you have the `searchParams,`, you can get the expected query string parameter being passed.
typescript
const userId = searchParams.get('id');
Now let’s pass the `userId` along with the API endpoint URL to filter the API response by `id`.
Here is the modified GET method,
typescript
const GET = async (request:any) => {
const { searchParams } = new URL(request.url);
const userId = searchParams.get('id');
const response = await fetch(`https://jsonplaceholder.typicode.com/users?id=${userId}`);
const responseData = await response.json();
return Response.json({"status":200, "data": responseData})
}
Save the changes above and make a GET request with a query string like http://localhost:3000/api/users?id=1 to get the ID-specific response.
Next, let’s look at how to create a POST API endpoint.
POST API Endpoint
To create a POST API endpoint, create another method called POST and export it.
typescript
const POST = () => {
return Response.json({"status":200, "data": "Data updated successfully"});
}
export {POST}
Save the above changes, and once you make a POST request to http://localhost:3000/api/users you’ll get the following response,
json
{
"status": 200,
"data": "Data updated successfully"
}
When posting data to an endpoint, you might send data to the API. Further, let’s see how to read data posted to the POST API endpoint.
Inside the POST method, you can define a parameter called `request`. We’ll be using the `request` parameter to read the data posted to the endpoint.
Calling `request.json()` returns the parameters passed in the body of the request. Let’s use it to read the request body and return the data in the response.
typescript
const POST = async (request: any) => {
const params = await request.json();
const name = params['name'];
return Response.json({"status":200, "data": "Data updated successfully", "name": name});
}
Save the above changes and try sending a POST request with `name` in the request body. The value of the `name` parameter will be returned in the response.
json
{
"status": 200,
"data": "Data updated successfully",
"name": "Roy"
}
Next, let’s create an API endpoint for DELETE requests.
DELETE API Endpoint
Create a function called DELETE in the `app/api/users/route.ts` file and also export the function.
typescript
const DELETE = async (request:any) => {
return Response.json({status : 200, message : "Data deleted successfully"});
}
export {GET, POST, DELETE}
Now if you try to make a DELETE request to the API endpoint http://localhost:3000/api/users you will be able to get the following response,
{
"status": 200,
"message": "Data deleted successfully"
}
Passing data to the DELETE endpoint will be required. It can be either as a query string that we saw in the GET method or in the request body as we saw in the POST method.
Let’s try passing in the body as we tried in the POST request. Here is how the modified DELETE method looks:
typescript
const DELETE = async (request:any) => {
const params = await request.json();
return Response.json({status : 200, message : "Data deleted successfully", params});
}
Now if you save the above code and hit the API endpoint with a DELETE request with some data in the request body, that data would be returned in the response.
So, when I hit the endpoint with the following JSON data,
json
{
"name": "Roy"
}
The response from the API is as shown,
json
{
"status": 200,
"message": "Data deleted successfully",
"params": {
"name": "Roy"
}
}
Similar to how we created API endpoints for GET, POST, and DELETE requests, endpoints for PUT and PATCH requests can also be created.
Wrapping it up
In this tutorial, you learned how to create API endpoints in Next.js 14 using App Router.
You learned how to create an API that accepts GET, POST, and DELETE requests. You can further extend it to create handlers for PATCH and PUT requests.