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

create-next-api-route

v1.0.1

Published

A beautiful abstraction on top of the Next.js API routes API, which allows for local and global middleware, better syntax, error handling, context objects.

Downloads

4

Readme

Create Next.js API routes

Read the article

Create Next.js API routes with a simpler more beautiful syntax that allows the following features:

  • Local middleware (runs on single endpoint only)
  • Global middleware (runs on all endpoints)
  • Global error handling
  • Global context object
  • Define method handlers in their own functions
  • Use express middleware
  • Automatic typing

Example:

import { createApiRouteCreator } from "./createApiRouteCreator";
import { fakeDb } from "./fakeDb";
import initMiddleware from "./initMiddleware";
import Cors from "cors";
import { NextApiRequest, NextApiResponse } from "next";

// Define new middleware (use express middleware with initMiddleware or define
// your own custom functions)
const corsMiddleware = initMiddleware(Cors());
const loggerMiddleware = async (req: NextApiRequest, res: NextApiResponse) => {
  console.log("Incoming", req.method, "request");
};

// Call the createApiRouteCreator to create a route creator with global
// properties.
export const createApiRoute = createApiRouteCreator({
  // Global middleware. These are called on all routes.
  middleware: [corsMiddleware, loggerMiddleware],

  // Unimplemented method handler, any time a route is called with a method
  // that does not exist, this will be called instead
  unimplementedMethod(req, res) {
    res.status(405).json({ message: "Unimplemented" });
  },

  // Global context object, will be provided to each handler and will be
  // constructed on every request
  createContext(req, res) {
    return {
      requestBodyString: JSON.stringify(req.body),
      db: fakeDb,
    };
  },

  // Global error handler, all thrown errors will end up here. Handle custom
  // errors as you wish, and handle all other unknown errors in some catch-all
  // way.
  handleError(req, res, error) {
    if (typeof error === "string") {
      return res.status(400).send({ message: error });
    }

    res.status(400).send({ message: "Something wen't wrong!" });
  },
});

// With the route creator, export its result as default in the api route file
// to construct the route.
export default createApiRoute({
  // Get request handler, fetches all todos for authenticated user
  async get(req, res, ctx) {
    const user = await requireUser(req); // Throws on unauthenticated
    const todos = await ctx.db.getTodosForUser(user.id);

    res.json({ todos });
  },

  // Post request handler, creates a todo for an authenticated user
  async post(req, res) {
    const user = await requireUser(req); // Throws on unauthenticated

    // Validate body, throw on invalid
    if (typeof req.body !== "string" || req.body === "") {
      throw "Request body not a string or empty string";
    }

    // Create
    const todo = await ctx.db.createTodo(req.body, user.id);

    res.status(201).json(todo);
  },
  // Local middleware, will only run for this endpoint
  middleware: [
    async (req, res) => {
      console.log("Called local middleware");
    },
  ],
});

Documentation

`createApiRouteCreator``

type Req = NextApiRequest;
type Res = NextApiResponse;

/**
 * Creates a `createApiRoute` function. See next snippet for documentation on
 * createApiRoute.
 */
createApiRouteCreator<Context>({

	/**
	 * Create any global context object for requests to access
	 */
  createContext(req: Req, res: Res): Context;

	/**
	 * Create any handler to handle requests to unimplemented methods
	 */
  unimplementedMethod: (req: Req, res: Res, ctx: Context) => any;

	/**
	 * List all global middleware functions
	 */
  middleware?: Array<(req: Req, res: Res) => Promise<void>>;

	/**
	 * Create a handler to handle all thrown errors
	 */
  handleError?: (req: Req, res: Res, error: unknown) => void;
})

createApiRoute

type Req = NextApiRequest;
type Res = NextApiResponse;

/**
 * Create the `createApiRoute` function with a `createApiRouteCreator` function.
 * See previous snippet
 */
const createApiRoute = createApiRouteCreator({ /* ... */ })

/**
 * Returns the route handler function which should be exported as default
 */
export default createApiRoute<Context>({
	/**
	 * All handlers for different methods
	 */
  get?: (req: Req, res: Res, ctx: Context) => any;
  post?: (req: Req, res: Res, ctx: Context) => any;
  put?: (req: Req, res: Res, ctx: Context) => any;
  patch?: (req: Req, res: Res, ctx: Context) => any;
	delete?: (req: Req, res: Res, ctx: Context) => any;

	/**
	 * All local middleware which will run only on this route
	 */
  middleware?: Array<(req: Req, res: Res) => Promise<void>>;
})

`initMiddleware``


const someExpressMiddleware = (req: Request, res: Response: next: Function) => {
  // ...
	if (somethingWrong) next(new Error("Failed"))
  else next();
}

/**
 * `initMiddleware` turns an express middleware which takes three arguments:
 * `req`, `res` and `next` and turns it into an async function which returns
 * a promise or throws and can be called with simply a request and a response.
 * ```
 */
const usableMiddleware = initMiddleware(someExpressMiddleware);

/**
 * Init middleware return value can be called directly as follows
 */
await usableMiddleware(req as NextApiRequest, res as NextApiResponse);

/**
 * Or in `createApiRoute` and `createApiRouteCreator`
 */
export default createApiRoute({
	/* ... */,
	middleware: [usableMiddleware]
})