Open mastepanoski opened 2 years ago
You could add support to typescript, rewriting withRest or adding compatibility through index.d.ts:
import type { NextApiRequest, NextApiResponse } from 'next' import Boom from '@hapi/boom' import Joi from 'joi' const defaultLogError = (err: Boom.Boom) => { // Only log internal server errors if (!err.isServer) { return } // Log original error if passed if (err.data && err.data.originalError) { err = err.data.originalError } console.error(err.stack) } const defaultSendError = (res: NextApiResponse, err: Boom.Boom) => { const { output } = err const { headers, statusCode, payload } = output Object.entries(headers).forEach(([key, value]) => res.setHeader(key, value || '') ) res.status(statusCode).json(payload) } /** * Wraps a HTTP request handler with validation against Joi schemas. * * @param {object} schemas - An object with `query`, `body` or `headers` keys and their associated Joi schemas. * Each of these schemas will be matched against the incoming request. * * @returns {Function} The HTTP handler that validates the request. * * @example * * const getSchema = { * query: Joi.object({ * id: Joi.string().required(), * }), * }; * * export default withRest({ * GET: withValidation(getSchema)(async req, res) => { * // Do something with `req.query.id` * * return { foo: 'bar' }; * }, * }); */ export const withValidation = <T = any, R = any>(schemas: Joi.PartialSchemaMap<T> | undefined) => (fn: (arg0: NextApiRequest, arg1: NextApiResponse<R>) => Promise<any>) => async (req: NextApiRequest, res: NextApiResponse) => { const joiSchema = Joi.object(schemas).unknown(true) let validated: { [x: string]: any } try { validated = await joiSchema.validateAsync(req) } catch (err: any) { throw Boom.badRequest(err.message, { originalError: err as Error }) } // Joi normalizes values, so we must copy things back to req ;['headers', 'body', 'query'].forEach((key: string) => { ;(req as any)[key] = validated[key] }) return fn(req, res) } /** * @typedef {Function} SendError * * @param {object} res - Node.js response object. * @param {Error} err - The Boom error object. */ /** * @typedef {Function} LogError * * @param {Error} err - The Boom error object. */ /** * Matches handlers defined in `methods` against the HTTP method, like `GET` or `POST`. * * @param {object.<string, Function>} methods - An object mapping HTTP methods to their handlers. * @param {object} options - The options. * @param {SendError} options.sendError - A function responsible to send Boom errors back to the client. * @param {LogError} options.logError - A function that logs errors. * * @returns {Function} The composed HTTP handler. * * @example * * export default withRest({ * GET: async (req, res) => { * // Do something... * * return { foo: 'bar' }; * }, * }); */ const withRest = ( methods: { [x: string]: any }, opts: { logError?: typeof defaultLogError sendError?: typeof defaultSendError } = { logError: defaultLogError, sendError: defaultSendError, } ) => { const options = { logError: defaultLogError, sendError: defaultSendError, ...opts, } return async (req: NextApiRequest, res: NextApiResponse) => { try { const method = methods && methods[req.method || 'unknown'] if (!method) { throw Boom.methodNotAllowed( `Method ${req.method} is not supported for this endpoint` ) } const json = await method(req, res) // Do nothing if the request is already sent (e.g.: a redirect was issued) if (res.headersSent) { if (json !== undefined) { options.logError( Boom.internal( 'You have sent the response inside your handler but still returned something. This error was not sent to the client, however you should probably not return a value in the handler.' ) // eslint-disable-line max-len ) } return } // Next.js doesn't support nulls as `RFC7159` dictates, but we do if (json == null) { res.setHeader('Content-Type', 'application/json') res.setHeader('Content-Length', '4') res.end('null') } else { res.json(json) } } catch (err: Error | Boom.Boom | any) { // Not an ApiError? Then wrap it into an ApiError and log it. let apiError = err if (!err.isBoom) { apiError = Boom.internal(undefined, { originalError: err }) } options.logError(apiError) options.sendError(res, apiError) } } } export default withRest
I think this library is not maintained anymore
You could add support to typescript, rewriting withRest or adding compatibility through index.d.ts: