SimpleNext.js

How to create a REST API with Next.js

Cover Image for How to create a REST API with Next.js
Marouane Reda
Marouane Reda
If you need to understand the basics of Next.js, i recommend this course. (Disclaimer : this is an affiliate link that may earn me a small commission, but with no extra cost to you if you choose to enroll)

You can easily create a REST API for your Next.js app by using the built-in API routes. This article will show an example of how this API can be created.

What is a REST API

REST is a set of architectural constraints. It is neither a protocol nor a standard. API developers can implement REST in a number of ways.

When a client issues a request through a RESTful API, the API transfers a representation of the state of the resource to the requestor or endpoint. This information, or representation, is provided over the HTTP protocol in one of the following formats: JSON (JavaScript Object Notation), HTML, XLT, Python, PHP, or plain text. The most commonly used programming language is JSON because, contrary to what the name suggests, it is not language dependent and can be read by humans as well as machines.

Another point to remember: Headers and parameters also play a major role in the HTTP methods of a RESTful API HTTP request, as they contain important identifying information about the request (metadata, authorization, URI, setting cached, cookies, etc.). There are request headers and response headers. Each has its own HTTP connection information and status codes.

A RESTful API must meet the following criteria:

  • A client-server architecture made up of clients, servers and resources, with requests managed via HTTP Stateless client-server communications, i.e. client information is never stored between GET requests, which must be handled separately, completely independently
  • The ability to cache data to streamline client-server interactions
  • A uniform interface between the components which allows a standardized transfer of information This implies that: the requested resources are identifiable and separate from the representations sent to the client; the resources can be manipulated by the client by means of the received representation, which contains sufficient information; the self-describing messages returned to the client contain enough detail to describe how the client should handle the information; the API has a hypertext / hypermedia, which allows the client to use hyperlinks to know all the other actions available after accessing a resource.
  • A layered system, invisible to the customer, which enables the different types of servers (for security, load balancing, etc.) involved in retrieving the requested information to be prioritized.
  • On-demand code (optional), i.e. the ability to send executable code from the server to the client (when it requests it) in order to extend the functionality of a client Although the REST API must meet all of these criteria, it is considered to be easier to use than a protocol such as Simple Object Access Protocol (SOAP), which is subject to specific constraints, including messaging. XML, integrated security and transaction compliance, which makes it heavier and slower.

Because REST is a set of directives implemented on demand, REST APIs are faster and lighter, and offer increased scalability. They are therefore ideal for the IoT (Internet of Things) and the development of mobile applications.

Create an example app

let's create a very simple app where we will retrieve users details using a REST API that we will create from scratch.

First let's create our app :

npx create-next-app rest_app
# or
yarn create next-app rest_app

then create index.js, where we fetch our data from the REST API that we will create later using SWR :

import useSwr from 'swr'
import Link from 'next/link'

const fetcher = (url) => fetch(url).then((res) => res.json())

export default function Index() {
  const { data, error } = useSwr('/api/users', fetcher)

  if (error) return <div>Failed to load users</div>
  if (!data) return <div>Loading...</div>

  return (
    <ul>
      {data.map((user) => (
        <li key={user.id}>
          <Link href="/user/[id]" as={`/user/${user.id}`}>
            <a>{`User ${user.id}`}</a>
          </Link>
        </li>
      ))}
    </ul>
  )
}

retrieve indidual user data

We want to hit the endpoint /users/[id] to retrieve data of the user with the identifier [id]. For this we will use Next.js Dynamic routing feature. We will first use the pages routing system in next.js by creating the users folder under /pages. in the users folder we will create [id].js file :

import { useRouter } from 'next/router'
import useSwr from 'swr'

const fetcher = (url) => fetch(url).then((res) => res.json())

export default function User() {
  const router = useRouter()
  const { data, error } = useSwr(
    router.query.id ? `/api/user/${router.query.id}` : null,
    fetcher
  )

  if (error) return <div>Failed to load user</div>
  if (!data) return <div>Loading...</div>

  return <div>{data.name}</div>
}

here by accessing the /users/[id] url, we send a GET request to our REST API /api/user/[id] endpoint, and then display the response.

We now need to create our REST API.

We will create our API by using Api routes system build into Next.js.

Any file inside the folder pages/api is mapped to /api/* and will be treated as an API endpoint instead of a page. They are server-side only bundles and won't increase your client-side bundle size.

For example, the following API route pages/api/user.js returns a json response with a status code of 200:

export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

For an API route to work, you need to export a function as default (a.k.a request handler), which then receives the following parameters:

req: An instance of http.IncomingMessage, plus some pre-built middlewares res: An instance of http.ServerResponse, plus some helper functions To handle different HTTP methods in an API route, you can use req.method in your request handler, like so:

export default function handler(req, res) {
  if (req.method === 'POST') {
    // Process a POST request
  } else {
    // Handle any other HTTP method
  }
}

So for our example, we create first the api folder under pages. Then we create the users.js file under the api folder, which will be our /api/users endpoint :

// Fake users data
const users = [{ id: 1 }, { id: 2 }, { id: 3 }]

export default function handler(req, res) {
  // Get data from your database
  res.status(200).json(users)
}

so when you hit the /api/users endpoint you will get back the users json data.

To create the /api/user/[id] endpoint, we create first the user folder under api, the inside the folder we create the [id].js file :

export default function userHandler(req, res) {
  const {
    query: { id, name },
    method,
  } = req

  switch (method) {
    case 'GET':
      // Get data from your database
      res.status(200).json({ id, name: `User ${id}` })
      break
    case 'PUT':
      // Update or create data in your database
      res.status(200).json({ id, name: name || `User ${id}` })
      break
    default:
      res.setHeader('Allow', ['GET', 'PUT'])
      res.status(405).end(`Method ${method} Not Allowed`)
  }
}

in this example we will get as a response the json with the id and the name of the user.

So in summary : in the pages/users/[id].js file , we send a request to /pages/api/users/[id].js (our API) and the response is in the data structure:

const { data, error } = useSwr(
    router.query.id ? `/api/user/${router.query.id}` : null,
    fetcher
  )

our API gives the response back in json format in the data structure , then we will display the name only :

return <div>{data.name}</div>

Conclusion

Creating a REST API is very straightforward in Next.js by using theAPI routes, as we have seen in this example.