npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

next-middleware-route

v1.0.0

Published

Add middlewares to next routes

Downloads

4

Readme

next-middleware-route

This library extends next routes with a middleware option in a simple manner.

Next supports middlewares natively, please check if the scope you need is already handled by it: https://nextjs.org/docs/advanced-features/middleware

Content

Installation

# npm
npm i next-middleware-route

# yarn
yarn add next-middleware-route

Typescript is natively supported, no @types/... package needed.

Usage

All usage examples are shown for Typescript. For Javascript just remove the type annotations.

This library provides two additional functionalities:

  • Add data to a request based on request data
  • Cancel a request and show an error message before it reaches the route

Defining middlewares

Add data

To extend the HttpContext we use merged interfaces.

import {NextApiRequest, NextApiResponse} from "next";
import {Middleware, IHttpContext} from "next-middleware-route";

// Add your data types to the IHttpContext interface
// Always make it optional as, most likely, not every route will have your middleware
declare module "next-middleware-route" {
  interface IHttpContext {
    customData?: string;
  }
}

// Add data to the IHttpContext 
// Return true as it should not interrupt the request
const customDataMiddleware: Middleware = {
  execute: async (ctx: IHttpContext, req: NextApiRequest, res: NextApiResponse) => {
    ctx.customData = "data";
    return true;
  }
}

export default customDataMiddleware;

The middleware will execute before the targeted request function is execute, and you will be able to access your ctx.customData in the targeted request.

Check and cancel request

import {NextApiRequest, NextApiResponse} from "next";
import {Middleware} from "next-middleware-route";

// Check request data and return false if failed
// If returned false the error defined is being used as response
const filterGetMiddleware: Middleware = {
  error: {
    code: 405,
    message: "Method not allowed"
  },
  execute: async (ctx: IHttpContext, req: NextApiRequest, res: NextApiResponse) => {
    return req.method != "GET";
    // You can return a custom error that differs from the one above like this:
    // return {code: 405, message: "Custom error"};
  }
}

export default filterGetMiddleware;

The default error handler responds with the following:

res.status(code).json({error: message});

Attaching middlewares to routes

To attach a middleware you wrap the actual route handler with a makeRoute and pass all middlewares as an option.

import type { NextApiRequest, NextApiResponse } from 'next'

import {IHttpContext, makeRoute, sendError} from "next-middleware-route";
import customDataMiddleware from "middlewares/customDataMiddleware";
import filterGetMiddleware from "middlewares/filterGetMiddleware";

async function handler(
  ctx: IHttpContext,
  req: NextApiRequest,
  res: NextApiResponse
) {
  const {customData} = ctx;

  if (!customData) {
    // Forgot to add customDataMiddleware to the middleware array
    return await sendError(res, 500, "customDataMiddleware did not run");
  }
  
  // All good, output the custom data
  return res.status(200).json({message: customData});
}

// Attach middlewares to the route and export the result as default
export default makeRoute(handler, {
  middlewares: [filterGetMiddleware, customDataMiddleware]
});

Custom error handling

You can define a custom error handler per route like this:

export default makeRoute(handler, {
  middlewares: [],
  errorHandler: async (res: NextApiResponse<T>, code: number, message: string): Promise<void> => {
    // Handle error data
    // Always send a response to not stall requests
  }
});

If you want it in all routes you can wrap the makeRoute with a custom makeMyRoute and use it instead of makeRoute:

import {makeRoute, sendError} from "next-middleware-route";

export default function makeMyRoute<T = unknown>(handler: MiddlewareRoute<T>, {
  middlewares = [],
  errorHandler = sendError
}: MakeRouteParameters<T>) {
  return makeRoute(handler, {
    middlewares: middlewares,
    
    // Use the per route error handler, otherwise your defined default
    errorhandler: errorHandler ?? async (res: NextApiResponse<T>, code: number, message: string): Promise<void> => {
      // Handle error data
      // Always send a response to not stall requests
    }
  })
}

Middlewares with parameters

If your middleware should have parameters you can wrap them in a function. Here is an example for multiple HttpMethods:

import {NextApiRequest, NextApiResponse} from "next";
import {makeRoute, sendError, Middleware, IHttpContext} from "next-middleware-route";


export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";

export default function methodMiddleware(methods: HttpMethod | HttpMethod[]): Middleware {
  return {
    error: {
      code: 405,
      message: "Method not allowed"
    },
    execute: async (ctx: IHttpContext, req: NextApiRequest, res: NextApiResponse): Promise<boolean> => {
      const {method} = req;
      const methodArray = Array.isArray(methods) ? methods : [methods];

      return !!method && methodArray.includes(method as HttpMethod);
    }
  }
}

You can use it like this:

export default makeRoute(handler, {
  middlewares: [methodMiddleware("GET")]
});

Parse body in middlewares

Every route that uses a middleware which does custom body parsing needs the following export:

export const config = {
  api: {
    bodyParser: false
  }
}