Giter Site home page Giter Site logo

neg4n / next-api-compose Goto Github PK

View Code? Open in Web Editor NEW
35.0 1.0 4.0 905 KB

๐Ÿงฌ Simple, dependency free, error aware and powerful utility to compose chain of multiple middleware into one Next.js API Route.

Home Page: https://www.npmjs.com/package/next-api-compose

License: MIT License

TypeScript 98.67% JavaScript 1.33%
next nextjs nextjs-plugin nextjs-api nextjs-api-routes nextjs-typescript hacktoberfest typescript express app-router-nextjs

next-api-compose's Introduction

next-api-compose example code theme aware

Next.js API Compose ยท version npm bundle size

Introduction

This library provides a hassle-free way of composing multiple middleware functions into one Next.js API Route Handler's method in the App Directory router.

Important

The 2.0.0 version of the library supports both app and pages directory oriented API utilities. If you're still using Pages Router and you want to migrate from versions below 2.0.0, please read migration guide and ocassionally consider checking out intro to the App Router.

Features

  • ๐Ÿ˜‡ Simple and powerful API
  • ๐Ÿš€ Designed both for Pages Router and App Router
  • ๐Ÿงช Production-ready. 100% test coverage, even type inference is tested!
  • ๐Ÿฅท Excellent TypeScript support
  • ๐Ÿงฌ Maintaining order of middleware chain
  • ๐Ÿ“ฆ No dependencies, small footprint

Installing and basic usage

Install the package by running:

npm i next-api-compose -S
# or
yarn add next-api-compose
# or
pnpm i next-api-compose

then create an API Route Handler in the App Directory:

in TypeScript (recommended)

import type { NextRequest } from "next/server";
import { compose } from "next-api-compose";

function someMiddleware(request: NextRequest & { foo: string }) {
  request.foo = "bar";
}

const { GET } = compose({
  GET: [
    [someMiddleware],
    (request /* This is automatically inferred */) => {
      return new Response(request.foo);
      //                         ^ (property) foo: string - autocomplete works here
    },
  ],
});

export { GET };

in JavaScript:

import { compose } from "next-api-compose";

function someMiddleware(request) {
  request.foo = "bar";
}

const { GET } = compose({
  GET: [
    [someMiddleware],
    (request) => {
      return new Response(request.foo);
    },
  ],
});

export { GET };

Error handling

Handling errors both in middleware and in the main handler is as simple as providing sharedErrorHandler to the compose function's second parameter (a.k.a compose settings). Main goal of the shared error handler is to provide clear and easy way to e.g. send the error metadata to Sentry or other error tracking service.

By default, shared error handler looks like this:

sharedErrorHandler: {
  handler: undefined;
  // ^^^^ This is the handler function. By default there is no handler, so the error is being just thrown.
  includeRouteHandler: false;
  // ^^^^^^^^^^^^^^^^ This toggles whether the route handler itself should be included in a error handled area.
  //                  By default only middlewares are being caught by the sharedErrorHandler
}

... and some usage example:

// [...]
function errorMiddleware() {
  throw new Error("foo");
}

const { GET } = compose(
  {
    GET: [
      [errorMiddleware],
      () => {
        // Unreachable code due to errorMiddleware throwing an error and halting the chain
        return new Response(JSON.stringify({ foo: "bar" }));
      },
    ],
  },
  {
    sharedErrorHandler: {
      handler: (_method, error) => {
        return new Response(JSON.stringify({ error: error.message }), {
          status: 500,
        });
      },
    },
  }
);
// [...]

will return {"error": "foo"} along with 500 status code instead of throwing an error.

Theory and caveats

  1. Unfortunately there is no way to dynamically export named ESModules (or at least I did not find a way) so you have to use export { GET, POST } syntax instead of something like export compose(...) if you're composing GET and POST methods :(

  2. Middleware is executed as specified in the per-method array, so if you want to execute middleware in a specific order, you have to be careful about it. Early returned new Response() halts the middleware chain.

Contributors

Igor
Igor

๐Ÿ’ป โš ๏ธ ๐Ÿ’ก
Maksymilian Grabka
Maksymilian Grabka

โš ๏ธ ๐Ÿ’ป
kacper3123
kacper3123

๐Ÿ“–

License and acknowledgements

The project is licensed under The MIT License. Thanks for all the contributions! Feel free to open an issue or a pull request even if it is just a question ๐Ÿ™Œ

next-api-compose's People

Contributors

allcontributors[bot] avatar kasin-it avatar mgrabka avatar neg4n avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

next-api-compose's Issues

Make use of generics in sharedErrorHandler

export type NextApiComposeOptions<
RequestType,
ResponseType = NextApiResponse,
DataType = any
> = {
sharedErrorHandler: (
error: Error,
request: NextApiRequest,
response: NextApiResponse
) => void | Promise<void>
middlewareChain: NextApiComposeMiddlewares<RequestType, ResponseType, DataType>
}

Create helper for configuring Next.js middleware

Some of Next.js middlewares accept configuration as first or last argument of the function. Middleware used with next-api-compose should have only one function parameter (NextApiHandler).

We can provide utility function for configuring these middleware easily. Of course - it can be done by hand but repeating "wrapper" code across the project while using chain composed of multiple middleware, it would be extremely painful.

Double execution of route handler

Next.js API Route handler after composition of middleware (the composition process seems ok) is executed twice. Needs further investigation and fix ASAP

Create compatibility helpers

Currently, next-api-compose relies heavily on (i guess) not popular way of writing middleware by combining many functions and callbacks.

Some kind of utility function for converting express or connect middleware to next-api-compose compatible middleware must be created.

Feature Request: allow adding another middleware array optional param, to be executed at the end of the chain

Suggestion:

import { compose } from 'next-api-compose'

export default compose([preWithBar, preWithFoo], [postWithBar, postWithFoo], (request, response) => {
  const { foo, bar } = request
  response.status(200).json({ foo, bar })
})

Some of the reasons:

  • Logging
  • APM performance tracing
  • fetch.waitUntil() to trigger custom business logic (purge/refresh cache, CRUD events)
  • Analytics
  • HTTP Edge Cache storage of the response body

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.