{"id":2303,"date":"2022-01-26T09:56:58","date_gmt":"2022-01-26T09:56:58","guid":{"rendered":"https:\/\/lvboard.infostore.in.ua\/?p=2303"},"modified":"2022-01-26T09:56:58","modified_gmt":"2022-01-26T09:56:58","slug":"building-full-stack-react-apps-with-next-js-api-routes","status":"publish","type":"post","link":"https:\/\/lvboard.infostore.in.ua\/?p=2303","title":{"rendered":"Building full-stack React apps with Next.js API routes"},"content":{"rendered":"\n<p>Besides Next.js being a great front-end framework for React, it also provides a simple way to build an API for your front-end &#8211; all in the same web app!<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>As of version 9, Next.js provides API routes that allows developers to create API endpoints using the Next.js folder structure. We can use API endpoints to build either a RESTful API, or a GraphQL API. This article will focus on a RESTful API for the sake of simplicity.<\/p>\n\n\n\n<p>With Next.js API routes, there&#8217;s no longer a need to set up a back-end Node.js server to build an API. Building out two separate projects for the front-end and back-end of an application introduces its own set of challenges. Next.js simplifies this process by becoming a full-stack web framework with the addition of API routes. Building and deploying a full-stack web app has never been faster and easier!<\/p>\n\n\n\n<h1 id=\"setting-up-api-routes\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#setting-up-api-routes\">?<\/a>Setting up API routes<\/h1>\n\n\n\n<p>API routes go in the <code>pages\/api<\/code> directory of a Next.js project.<\/p>\n\n\n\n<p>When a file or folder is added to this <code>pages\/api<\/code> folder, Next.js will create an API endpoint URL for it. Creating a <code>pages\/api\/users.ts<\/code> file will create an <code>\/api\/users<\/code> API endpoint. We can also create an <code>\/api\/users<\/code> API endpoint by creating a <code>pages\/api\/users\/index.ts<\/code> file.<\/p>\n\n\n\n<p>To create a dynamic API route for a specific user, we can create a <code>pages\/api\/users\/[id].ts<\/code> file. This dynamic route will match requests such as <code>\/api\/users\/1<\/code>.<\/p>\n\n\n\n<p>Just like the <code>pages<\/code> folder maps its files and folders to URLs that can be visited in a web browser, the <code>pages\/api<\/code> folder maps its files and folders to API endpoint URLs.<\/p>\n\n\n\n<h1 id=\"creating-api-routes\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#creating-api-routes\">?<\/a>Creating API routes<\/h1>\n\n\n\n<p>To begin, let&#8217;s create a new Next.js project called <code>nextjs-full-stack<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx create-next-app full-stack-nextjs\n\ncd full-stack-nextjs<\/code><\/pre>\n\n\n\n<p>If you prefer using TypeScript with Next.js, you can use <code>npx create-next-app --ts<\/code> instead. For this article, we&#8217;ll just use JavaScript.<\/p>\n\n\n\n<p>Notice that newly created Next.js project contains a <code>pages\/api\/hello.js<\/code> file. An <code>\/api\/hello<\/code> API endpoint has already been provided for us. Let&#8217;s run the project using <code>npm run dev<\/code> to try this API endpoint.<\/p>\n\n\n\n<p>Visit <code>http:\/\/localhost:3000\/api\/hello<\/code> in a web browser. You should see the following response.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{ \"name\": \"John Doe\" }\n<\/code><\/pre>\n\n\n\n<h1 id=\"understanding-api-routes\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#understanding-api-routes\">?<\/a>Understanding API routes<\/h1>\n\n\n\n<p>Let&#8217;s take a look at the code in the <code>pages\/api\/hello.js<\/code> file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export default function handler(req, res) {\n  res.status(200).json({ name: 'John Doe' })\n}<\/code><\/pre>\n\n\n\n<p>The default export in files that are found within the <code>api<\/code> folder must be a function. Each function is a handler for a particular route. Asynchronous functions are also supported for cases where requests need to be made to external APIs or a database.<\/p>\n\n\n\n<p>When running the Next.js project locally, it creates a Node.js server and passes the <code>request<\/code> and <code>response<\/code> objects from the server into the handler function of the requested endpoint.<\/p>\n\n\n\n<h1 id=\"a-dynamic-route\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#a-dynamic-route\">?<\/a>A dynamic route<\/h1>\n\n\n\n<p>Let&#8217;s create a <code>pages\/api\/users\/[id].js<\/code> file to create an API route for a specific user. Let&#8217;s add the following code within this file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const users = &#91;\n\t{ id: 1, name: 'John Smith' },\n\t{ id: 2, name: 'Jane Doe' },\n];\n\nexport default (req, res) =&gt; {\n  const { query: { id } } = req;\n\n  res.json({ \n    ...users.find(user =&gt; user.id === parseInt(id)),\n  });\n}<\/code><\/pre>\n\n\n\n<p>For the purposes of creating an example, we mocked up a list of users within the file. More realistic usage might involve querying a database for the requested user.<\/p>\n\n\n\n<p>The <code>id<\/code> value is retrieved from the request query parameter, and then used to find the corresponding user object in the list of users. Keep in mind that the <code>id<\/code> from the request is a string, so we must parse it to an integer in order to perform a user lookup by id on the users list.<\/p>\n\n\n\n<p>Visit <code>http:\/\/localhost:3000\/api\/users\/1<\/code> in a web browser. You should see the following response.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{ \"id\": 1, \"name\": \"John Smith\" }<\/code><\/pre>\n\n\n\n<h1 id=\"returning-an-error\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#returning-an-error\">?<\/a>Returning an error<\/h1>\n\n\n\n<p>We can modify the user endpoint we just created to return an error when the requested user id is not found in a list of users.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const users = &#91;\n\t{ id: 1, name: 'John Smith' },\n\t{ id: 2, name: 'Jane Doe' },\n];\n\nexport default (req, res) =&gt; {\n  const { query: { id } } = req;\n\n  const user = users.find(user =&gt; user.id === parseInt(id));\n  if (!user) {\n    return res.status(404).json({\n      status: 404,\n      message: 'Not Found'\n    });\n  }\n\n  res.json({ ...user });\n}<\/code><\/pre>\n\n\n\n<p>Visit <code>http:\/\/localhost:3000\/api\/users\/3<\/code> in a web browser. You should see the following response since no user with an <code>id<\/code> of <code>3<\/code> exists.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{ \"status\": 404, \"message\": \"Not Found\" }<\/code><\/pre>\n\n\n\n<h1 id=\"handling-multiple-http-verbs\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#handling-multiple-http-verbs\">?<\/a>Handling multiple HTTP verbs<\/h1>\n\n\n\n<p>Next.js API routes allow us to support multiple HTTP verbs for the same endpoint all in one file. The HTTP verbs that we want to support for a single API endpoint are specified in the request handler function.<\/p>\n\n\n\n<p>Let&#8217;s create a <code>pages\/api\/users\/index.js<\/code> file to create an API route for all users. We want this endpoint to support <code>GET<\/code> requests to get all users and <code>POST<\/code> requests to create users. Let&#8217;s add the following code within this file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export default (req, res) =&gt; {\n  const { method } = req;\n\n  switch (method) {\n    case 'GET':\n      res.json({ method: 'GET', endpoint: 'Users' });\n      break;\n    case 'POST':\n      res.json({ method: 'POST', endpoint: 'Users' });\n      break;\n    default:\n      res.setHeader('Allow', &#91;'GET', 'POST']);\n      res.status(405).end(`Method ${method} Not Allowed`);\n      break;\n  }\n}<\/code><\/pre>\n\n\n\n<p>The <code>req.method<\/code> value will tell us what HTTP verb was used to make the request. We can use a <code>switch<\/code> statement to support multiple HTTP verbs for the same endpoint. Any HTTP requests that are not <code>GET<\/code> or <code>POST<\/code>, requests will enter the <code>default<\/code> case and return a <code>405 Method Not Allowed<\/code> error.<\/p>\n\n\n\n<p>Visit <code>http:\/\/localhost:3000\/api\/users<\/code> in a web browser. You should see the following response.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{ \"method\": \"GET\", \"endpoint\": \"Users\" }<\/code><\/pre>\n\n\n\n<p>We can use an API platform like Postman or Insomnia to test <code>POST<\/code>, <code>PUT<\/code>, and <code>DELETE<\/code> requests to this API endpoint.<\/p>\n\n\n\n<p>Testing the <code>POST<\/code> request will return the following response.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"method\": \"POST\",\n  \"endpoint\": \"Users\"\n}<\/code><\/pre>\n\n\n\n<p>Testing <code>PUT<\/code> and <code>DELETE<\/code> requests will return <code>Method Not Allowed<\/code> errors with a <code>405 Method Not Allowed<\/code> response code.<\/p>\n\n\n\n<h1 id=\"using-api-routes-from-the-front-end\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#using-api-routes-from-the-front-end\">?<\/a>Using API routes from the front-end<\/h1>\n\n\n\n<p>Let&#8217;s create a <code>users\/[id].js<\/code> page to retrieve a specific user when the page loads, and then mimic a save profile operation when the form on the page is submitted.<\/p>\n\n\n\n<p>We will use client-side rendering within Next.js for this page. Client-side rendering is when the client makes requests for API data. The approach used in this example can also apply for pages that use server-side Rendering (SSR).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { useEffect, useState } from 'react';\nimport { useRouter } from 'next\/router';\n\nexport default function User() {\n  const router = useRouter();\n  const { id } = router.query;\n  const &#91;name, setName] = useState();\n\n  \/\/ GET request to get a user\n  useEffect(() =&gt; {\n    \/\/ wait for the useRouter hook to asynchronously get the query id\n    if (!id) {\n      return;\n    }\n\n    const fetchUser = async () =&gt; {\n      const response = await fetch(`\/api\/users\/${id}`, {\n        method: \"GET\",\n        headers: {\n          \"Content-Type\": \"application\/json\"\n        },\n      });\n\n      if (!response.ok) {\n        throw new Error(`Error: ${response.status}`);\n      }\n\n      const user = await response.json();\n      setName(user?.name);\n    }\n\n    fetchUser();\n  }, &#91;id]);\n\n  \/\/ POST request to mimic the saving of a user\n  const onSubmit = async (e) =&gt; {\n    e.preventDefault();\n    const response = await fetch(\"\/api\/users\", {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application\/json\"\n      },\n      body: JSON.stringify({}),\n    });\n\n    if (!response.ok) {\n      throw new Error(`Error: ${response.status}`);\n    }\n\n    const data = await response.json();\n    console.log('POST: ', data);\n  };\n\n  return (\n    &lt;div&gt;\n      &lt;h1&gt;User Form&lt;\/h1&gt;\n      &lt;form onSubmit={onSubmit}&gt;\n        &lt;div&gt;\n          &lt;label htmlFor=\"name\"&gt;Name&lt;\/label&gt;\n          &lt;input \n            type=\"text\" \n            id=\"name\" \n            name=\"name\" \n            value={name ?? ''} \n            onChange={(e) =&gt; setName(e.target.value)}\n          \/&gt;\n        &lt;\/div&gt;\n        &lt;button type=\"submit\"&gt;Submit&lt;\/button&gt;\n      &lt;\/form&gt;\n    &lt;\/div&gt;\n  );\n}<\/code><\/pre>\n\n\n\n<p>To retrieve a user by <code>id<\/code> when the page loads, we can use the React <code>useEffect<\/code> hook with the <code>id<\/code> as a dependency. The browser-supported Fetch API is used to make a <code>GET<\/code> request to <code>\/api\/users\/[id]<\/code>. Async\/await is used to wait for this asynchronous request to complete. Once it is completed, the user&#8217;s name is saved to the component state using <code>setName<\/code>, and displayed within the input text box.<\/p>\n\n\n\n<p>When the form is submitted, a <code>POST<\/code> request is made to the <code>\/api\/users<\/code> API route that we created earlier. To keep things simple, the response of the request is then logged to the console.<\/p>\n\n\n\n<h1 id=\"conlusion\"><a href=\"https:\/\/www.thisdot.co\/blog\/building-full-stack-react-apps-with-next-js-api-routes#conlusion\">?<\/a>Conlusion<\/h1>\n\n\n\n<p>Next.js makes it fast and easy to build an API for your next project. A very good use case to get started with Next.js API routes is for the implementation of CRUD operations to handle form input.<\/p>\n\n\n\n<p>API endpoints are created as Node.js serverless functions. You can build out your entire application&#8217;s API with Next.js API routes. Go ahead and build something awesome with them!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Besides Next.js being a great front-end framework for React, it also provides a simple way to build an API for your front-end &#8211; all in the same web app!<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[30],"tags":[161,65],"_links":{"self":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2303"}],"collection":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2303"}],"version-history":[{"count":1,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2303\/revisions"}],"predecessor-version":[{"id":2304,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2303\/revisions\/2304"}],"wp:attachment":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}