Snippets
Middleware-like wrappers around Next.js API Routes and Route Handlers (See also: TS Wrappers)
TS
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
/**
* Wrapper around a Next.js API handler that attaches an extra
* `wrapped` property to the request, and logs to the console.
*
* @param handler
* @returns
*/
export const withWrapper = <
Req extends NextApiRequest & { wrapped?: boolean },
Res extends NextApiResponse
>(
handler: (req: Req, res: Res) => ReturnType<NextApiHandler>
) => {
// Define the new handler to replace the original one.
function newHandler(this: any, req: Req, res: Res) {
req.wrapped = true;
// Invoke the original handler
const result = handler.call(this, req, res);
// Return the original function result
return result;
}
// Return the new handler to be used in place of the old one
return newHandler;
};
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
/**
* Wrapper around a Next.js API handler that attaches an extra
* `wrapped` property to the request, and logs to the console.
*
* @param handler
* @returns
*/
export const withWrapper = <
Req extends NextApiRequest & { wrapped?: boolean },
Res extends NextApiResponse
>(
handler: (req: Req, res: Res) => ReturnType<NextApiHandler>
) => {
// Define the new handler to replace the original one.
function newHandler(this: any, req: Req, res: Res) {
req.wrapped = true;
// Invoke the original handler
const result = handler.call(this, req, res);
// Return the original function result
return result;
}
// Return the new handler to be used in place of the old one
return newHandler;
};
Examples
withLogging
Example showing how to log requests to an API handler
TS
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
/**
* A wrapper that logs
* each stage of the request.
*/
export function withLogging<
Req extends NextApiRequest & { loggingEnabled?: boolean },
Res extends NextApiResponse
>(handler: (req: Req, res: Res) => ReturnType<NextApiHandler>) {
// Define the new function to replace the original one.
async function newHandler(this: any, req: Req, res: Res) {
req.loggingEnabled = true;
const start = Date.now();
console.log(`[${req.method}] ${req.url} started.`);
try {
const result = await handler.call(this, req, res);
console.log(`[${req.method}] ${req.url} succeeded.`);
return result;
} catch (e) {
res.status(500).send({ message: "Your request failed" });
console.log(`[${req.method}] ${req.url} failed.`);
}
const stop = Date.now();
console.log(`[${req.method}] ${req.url} took ${stop - start}ms.`);
}
// Return the new function to be used in place of the wrapped function
return newHandler;
}
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
/**
* A wrapper that logs
* each stage of the request.
*/
export function withLogging<
Req extends NextApiRequest & { loggingEnabled?: boolean },
Res extends NextApiResponse
>(handler: (req: Req, res: Res) => ReturnType<NextApiHandler>) {
// Define the new function to replace the original one.
async function newHandler(this: any, req: Req, res: Res) {
req.loggingEnabled = true;
const start = Date.now();
console.log(`[${req.method}] ${req.url} started.`);
try {
const result = await handler.call(this, req, res);
console.log(`[${req.method}] ${req.url} succeeded.`);
return result;
} catch (e) {
res.status(500).send({ message: "Your request failed" });
console.log(`[${req.method}] ${req.url} failed.`);
}
const stop = Date.now();
console.log(`[${req.method}] ${req.url} took ${stop - start}ms.`);
}
// Return the new function to be used in place of the wrapped function
return newHandler;
}
pages/api/hello.ts
Using a wrapper inside a Next.js API handler file
TS
// pages/api/hello.ts
import { NextApiResponse } from "next";
import { withLogging } from "./withLogging";
export default withLogging(function handler(
req,
res: NextApiResponse<{ message: string }>
) {
if (req.loggingEnabled) {
res.setHeader("X-Logging-Enabled", req.loggingEnabled.toString());
}
res.json({
message: "Hello world!",
});
});
// pages/api/hello.ts
import { NextApiResponse } from "next";
import { withLogging } from "./withLogging";
export default withLogging(function handler(
req,
res: NextApiResponse<{ message: string }>
) {
if (req.loggingEnabled) {
res.setHeader("X-Logging-Enabled", req.loggingEnabled.toString());
}
res.json({
message: "Hello world!",
});
});