Front-End Web & Mobile

Next.js API Routes with AWS Amplify

Next.js is a popular React framework that enables server-side rendering and static site generation for React apps. It makes building full-stack React apps incredibly simple. Developers love Next.js over other solutions because it handles a lot of the difficult configuration required for server-side rendering and static site generation automatically. It has builtin support for styling, routing, bundling, and more. Next.js apps are also very performant, search engine optimized, and can be deployed easily to hosting providers with a single command. The flexibility, simplicity, and features of Next.js make it a top choice for building production React applications.

What are Next.js API routes?

When building APIs to power your application, Next.js is more focused on hybrid apps with server-side rendering along with Next.js API routes to provide an effective, integrated solution for building APIs.  While Express may be simpler to set up than Next.js if you’re building an API-only app due to its flexibility in how you structure your app.

A separate Express API server requires building and maintaining a whole separate app setting up all the optimizations and infrastructure that comes built-in with Next.js API routes. This adds complexity to your stack and deployment. With API routes, you can build APIs directly in your Next.js app without needing another app. This simplifies your architecture and deployment process.

The file-system based routing of Next.js API routes provide a low barrier to entry and makes the endpoints very intuitive to work with. Simply create a file at the route you want to handle, like pages/api/users.js, export a function and the route is instantly available and fully integrated into the Next.js framework, so you get benefits like fast refresh in development, easy CORS handling, environment variables, and middleware support.

AWS Amplify is a set of purpose-built tools and features that enables frontend web and mobile developers to quickly and easily build full-stack applications on AWS including Next.js applications with API routes.  Deployment of Next.js API routes to AWS Amplify Hosting is fully managed through the AWS Amplify CLI. Environment Variables can be managed in Amplify Hosting to securely access external services and AWS Amplify Libraries provide access to AWS AppSync APIs and Amazon Cognito users.

Next.js API routes with Amplify and AWS AppSync

An example of using Next.js API routes in Amplify projects is a Todo application that needs to process user submitted data against a third-party backend system.

In the app, the customer submits a todo via the UI and a third-party backend system processes the text and compares it against previously completed todos for the user.  The result returned is an “optimized” todo with detailed information including time the todo should be completed, tags, and project or area.

For example, when a customer submits “Walk the dog”, the backend system returns “Walk the dog #personal 7:30am” because it has determined that this is a good time to schedule a reminder for this todo based on historical completions of similar tasks and that it is a personal task.

Below is an implementation of the pages/api/optimizeTodo.js Next.js API route that receives the todo and sends it to the third-party backend system to return the optimized version of what was submitted.  The response, optimizedTodo, is written to AWS AppSync using the Amplify Library along with the original todo.

// pages/api/optimizeTodo.js

import { Amplify, withSSRContext } from "aws-amplify";
import awsExports from "../../src/aws-exports";
import { createTodo } from "../../src/graphql/mutations";

Amplify.configure({ ...awsExports });

export default async (req, res) => {
  const SSR = withSSRContext({ req });
  const { todo } = req.body;

  // Send todo to backend system for processing
  const backendResponse = await fetch(process.env.BACKEND_API_ENDPOINT, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${process.env.BACKEND_API_KEY}`,
    },
    body: JSON.stringify({
      todo
    }),
  });
  const { optimizedTodo } = await backendResponse.json();

  // Write original `todo` and `optimizedTodo` to AppSync using Amplify
  const { data } = await SSR.API.graphql({
    query: createTodo,
    variables: {
      input: { 
        todo,
        optimizedTodo
      }
    },
  });

  res.status(200).json({ result: optimizedTodo });
};

In general, it is preferable to make API calls from Next.js API routes rather than client side code. Doing so provides several benefits including security in that API routes enable server-side API calls which are more secure than exposing API keys directly in client side code and any complex logic or transformations of API response data is better suited to be done on the server rather than the client.the abstraction of complex logic.

Conclusion

In summary, Next.js API routes simplify your stack, speed up development, and provide an optimized API experience – all from directly within your Next.js app.

With Next.js API routes, you get a fast, optimized API development experience without the added complexity of another server in your stack.  They speed up development and reduce infrastructure needs while providing a seamless experience integrated with other features and benefit from the Next.js production optimizations like bundling, minification, and prerendering.