moxystudio / next-rest-api Goto Github PK
View Code? Open in Web Editor NEWAims to ease the development of REST APIs in Next.js
License: MIT License
Aims to ease the development of REST APIs in Next.js
License: MIT License
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.