next-serve

fetch based abstraction for serverless request handlers

Usage no npm install needed!

<script type="module">
  import nextServe from 'https://cdn.skypack.dev/next-serve';
</script>

README

next-serve

Create http handlers using fetch primitives. Takes a request listener, defined in the primitives of the fetch API, and returns a clasic node.js request listener for it. It's targetted at Zeit now functions, but can also be used with plain http or express.

Installation:

npm install --save next-serve

Example usage

Serve it with now or as a next.js api route.

import { serve, Response } from 'next-serve';

export default serve({ request }) => {
  return Response.json({ url: request.url });
});

Or using node.js http.

import { createServer } from 'http';
import { serve, Response } from 'next-serve';

const server = createServer(serve({ request }) => {
  return Response.json({ url: request.url });
}).listen(3000);

Features

Familiar interface, duality with web APIs.

import { serve, Response } from 'next-serve';

export default serve(({ request }) => {
  const { pathname } = new URL(request.url);
  switch (pathname) {
    case '/hello': return new Response('hello');
    case '/world': return new Response('world');
    default: return new Response(null, { status: 404 });
  }
});

Serving JSON

import { serve, Response } from 'next-serve';

export default serve(() => Response.json({ hello: 'world' }));

Serving redirects

import { serve, Response } from 'next-serve';
export default serve(() => Response.redirect('/somewhere/else', 302));

Handling request bodies

import { serve, Response } from 'next-serve';
export default serve(async ({ request }) => {
  if (request.method !== 'POST') {
    return new Response(null, { status: 405 })
  }
  const body = await request.json();
  return Response.json({ hello: 'world' });
});

Middleware can be achieved through function composition

import { ServeHandler, serve, Response, ServeContext } from 'next-serve';

async function fetchUserByToken(token: string | null) {
  return token ? 'Johnny' : undefined;
}

export function withAuthentication<C extends ServeContext>(
  handler: ServeHandler<C & { user: string }>
): ServeHandler<C> {
  return async ctx => {
    const token = ctx.request.headers.get('authorization');
    const user: string | undefined = await fetchUserByToken(token);
    if (!user) {
      return new Response('Get out!', { status: 401 });
    }
    return handler({ ...ctx, user });
  };
}

export function withServerTiming(handler: ServeHandler): ServeHandler {
  return async ctx => {
    const start = Date.now();
    const response = await handler(ctx);
    const duration = Date.now() - start;
    response.headers.set('server-timing', `total;dur=${duration}`);
    return response;
  };
}

export default serve(
  withServerTiming(
    withAuthentication(({ user }) => {
      return Response.json({ user });
    })
  )
);

API

WIP