Estoy trabajando en Rutas API en Next.js con cada ruta estructurada de la siguiente manera:
import { NextApiRequest, NextApiResponse } from "next"; export default async (req: NextApiRequest, res: NextApiResponse) => { const { query } = req; try { switch (req.method) { case "GET": // Do some GET stuff res.status(200).send(result); break; case "POST": // Do some POST stuff res.status(200).send(result); break; default: // No Matched Method res.status(405).send("Method Not Allowed"); break; } } catch (e) { // Unprocessable Entity res.status(422).send(e); } }; Como puede ver, el caso default y la parte de catch se duplicarán en todos los archivos. Entonces queria saber:
Aquí está mi idea de una solución si no hay soporte incorporado:
export default . Intenté implementar esto, pero me quedé bloqueado al acceder a los objetos req y res como en el bloque de código a continuación. const wrapAPICall = async ( fn: (req: NextApiRequest, res: NextApiResponse) => void ) => { try { await fn(req, res); // Can't access req, res here } catch (e) { res.status(422).send(e); // Also can't access req, res here } finally { if (!res.headersSent) res.status(405).send("Method Not Allowed"); } }; const apiCall = async (req: NextApiRequest, res: NextApiResponse) => { // Does some API stuff }; export default wrapAPICall(apiCall);Encontré otra solución en lugar de escribir un contenedor personalizado: usar next-connect que es un middleware de enrutamiento para Next.js
El siguiente código produce los mismos resultados que una solución contenedora.
import { NextApiRequest, NextApiResponse } from "next"; import nc from "next-connect"; // Handle Error Here const handler = nc({ onError: (err, req: NextApiRequest, res: NextApiResponse) => { res.status(500).end(err.toString()); }, onNoMatch: (req: NextApiRequest, res: NextApiResponse) => { res.status(405).send("Method Not Allowed"); }, }); handler .get(async (req: NextApiRequest, res: NextApiResponse) => { // Do some GET stuff res.status(200).json(...); }) .post(async (req: NextApiRequest, res: NextApiResponse) => { // Do some POST stuff res.status(200).json(...); }); export default handler;Next.js separa las rutas API en muchos archivos si desea que el controlador sea reutilizable, hágalo así.
/modules/Utils.ts
export const apiHandler = { onError: (err, req: NextApiRequest, res: NextApiResponse) => { res.status(500).end(err.toString()); }, onNoMatch: (req: NextApiRequest, res: NextApiResponse) => { res.status(405).send("Method Not Allowed"); }, }; /pages/api/index.ts
import nc from "next-connect"; import { apiHandler } from "../modules/Utils"; const handler = nc(apiHandler); // Use handler exported from Utils handler .get((req, res) => {...}) .post((req, res) => {...}); export default handler;Creo que su solución de envoltura es sólida. Para que funcione, solo necesita devolver una función del contenedor.
const wrapAPICall = ( fn: (req: NextApiRequest, res: NextApiResponse) => void ) => { return async (req: NextApiRequest, res: NextApiResponse) => { try { await fn(req, res); } catch (e) { res.status(422).send(e); } finally { if (!res.headersSent) res.status(405).send("Method Not Allowed"); } } };