Middleware is regarded as one of the coolest features released in Next.js 12 because it has a lot of utility in modern applications, like working together with Vercel Edge Functions.
The term middleware is not a new one. Frameworks, like Express.js, use middleware to intercept an HTTP request and process it before it reaches the route handler.
So, in this post, we’ll learn how middleware works with Edge Functions and why it’s important to know. Now, let’s get started!
Next.js middleware
In Next.js, middleware is a simple piece of code that allows us to change the response to a request before it finishes. Based on a user’s request, we can rewrite, redirect, add headers, or even stream HTML.
The exciting thing about using middleware is that it runs before every request made on Next.js. This means that when a user requests any page or API route, the middleware logic runs right before the request.
To create a middleware in Next.js, create a file called _middleware.js
or _middleware.ts
under pages
or api
. Within the file, export the middleware function, as shown below:
import type { NextFetchEvent, NextRequest } from 'next/server'; export default function middleware( request: NextRequest, event: NextFetchEvent, ) { // return your new response; }
Its API is built on native FetchEvent
, Response
, and Request
objects. These native web API objects have been extended to provide you with more control over how you manipulate and configure a response based on incoming requests.
With the middleware function signature, the waitUntil()
method is included in the NextFetchEvent
object, which extends the native FetchEvent
object:
import type { NextFetchEvent } from 'next/server'; import type { NextRequest } from 'next/server'; export type Middleware = ( request: NextRequest, event: NextFetchEvent, ) => Promise<Response | undefined> | Response | undefined;
After the response is sent, you can use the waitUntil()
method to extend the function’s execution. In practice, this means that if you have other background work to do, you can send a response and then continue the function execution.
Integrations with logging tools such as Sentry or DataDog are yet another factor why you might need waitUntil()
. You can send logs of response times, errors, API call durations, or total performance metrics after the response has been sent.
The native Request
object is extended by the NextRequest
object, while the native Response
object is extended by the NextResponse
object.
Middleware gives us complete flexibility to run our code before a request completes. You can modify the response based on a user’s incoming request by rewriting, redirecting, adding headers, or even streaming HTML.
Another advantage is that middleware provides a more efficient way to share logic between pages, allowing you to keep your code DRY and efficient.
However, middleware is still in beta, so you might encounter some bugs while working with it.
How does Next.js middleware work?
Vercel’s Edge Functions, which run on the V8 Engine, are used by Next.js’ middleware. Google maintains the V8 Engine, a JavaScript engine written in C++, and it is significantly faster than running Node.js in a virtual machine or container, and Vercel claims that these Edge Functions are instantaneous.
The Edge Functions are placed between the user’s request and the server, so the middleware runs before that request completes.
Understanding Edge Functions
If you’ve ever used serverless functions, you’ll understand Edge Functions. To get a better understanding, we’ll compare Edge Functions to serverless functions.
When you deploy a serverless function to Vercel, it’s deployed to a server somewhere in the world. The request made to that function will then execute where the server is located.
If a request is made to a server close to that location, it will happen quickly. But if a request is made to the server from a location very far away, then the response will be much slower.
This is where Edge Functions can help. In simplicity, Edge Functions are serverless functions that run geographically close to a user, making the request very fast regardless of where that user might be.
When deploying a Next.js application to Vercel, the middleware will deploy as Edge Functions to all regions around the world. This means that instead of a function sitting on a server, it will sit on multiple servers.
Here, the Edge Functions use middleware. One of the unique things about Edge Functions is that they are a lot smaller than our typical serverless functions. They also run on V8 runtime, which makes it 100x faster than Node.js in containers or virtual machines.
Why are Edge Functions and middleware important?
Understanding how to use middleware with Edge Functions solves the issue of sharing a common login across multiple applications such as authentication, bot protection, redirects, browser support, feature flags, A/B testing, server-side analytics, logging, and geolocations efficiently.
With the help of Edge Functions, middleware can run faster like static web applications because they help to reduce latency and eliminate cold startup.
With Edge Functions, we can run our files on multiple geolocations, allowing regions closest to the user to respond to the user’s request. This provides faster user requests regardless of their geographic location.
Traditionally, web content is served from a CDN to an end user to increase speed. However, because these are static pages, we lose dynamic content. Also, we use server-side rendering to get dynamic content from the server, but we lose speed.
However, by deploying our middleware to the Edge like a CDN, we bring our server logic closer to our visitors’ origin. As a result, we have speed as well as personalization for the users.
As a developer, you can now build and deploy your website and then cache the result in CDNs across the world.
Basic password authentication implementation
Let’s see how we can use middleware in our API for authentication by creating a basic password authentication and testing it with Postman.
Postman is an API platform that allows you to create and use APIs faster by streamlining collaboration and simplifying the API lifecycle.
First, open up the terminal and create a folder where we want our project installed:
mkdir next_middleware
cd
into the recently created folder, install Next.js, and give your project a name:
npx create-next-app@latest
Now that we’ve done that, let’s create our middleware. Inside our pages/api
folder, let’s create a file called _middleware.js
. Next, let’s paste in the following:
import { NextResponse } from 'next/server' export function middleware(req) { const basicAuth = req.headers.get('authorization') if (basicAuth) { const auth = basicAuth.split(' ')[1] const [user, pwd] = Buffer.from(auth, 'base64').toString().split(':') if (user === 'mydmin' && pwd === 'mypassword') { return NextResponse.next() } } return new Response('Auth required', { status: 401, headers: { 'WWW-Authenticate': 'Basic realm="Secure Area"', }, }) }
Inside the middleware
function, we first get the authorization header; if the authorization header is set, we pass the username and password from the header and check if the user equals our parameters (username and password).
If they do, return the NextResponse
and call the next function. What this next function does is return the NextResponse
that continues the middleware chain. If the username and password did not match, then we return a new response saying authentication is required.
Let’s test this out using Postman by making an API request. But first, we need to start up our app:
npm run dev
Then, open Postman and make a new request; our request should be made to http://localhost:3000/api/hello.
Click on the authorization tab and select Basic Auth. Input the correct user credentials and this should be our result:
And, when we input a wrong username or password, we get the following:
We can see how easy it is to add basic authentication to API routes. By adding the middleware file, we get the authentication of all endpoints in our API. This is much easier and more convenient.
Conclusion
With its ability to solve basic problems like authentication and geolocation, middleware is an outstanding feature, and with the help of Edge Functions, middleware can run faster like static web applications.
The post Using Next.js’ middleware and Edge Functions appeared first on LogRocket Blog.
from LogRocket Blog https://ift.tt/eWcNjrG
via Read more