Skip to content

Instantly share code, notes, and snippets.

@WEEFAA
Last active July 27, 2022 06:03
Show Gist options
  • Select an option

  • Save WEEFAA/7dd5c1ffb2f5c54e4a1417cf9fb06aa6 to your computer and use it in GitHub Desktop.

Select an option

Save WEEFAA/7dd5c1ffb2f5c54e4a1417cf9fb06aa6 to your computer and use it in GitHub Desktop.
[NextJS] custom controller class
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"
// checkout NextJS 'NextApiResponse' generic,
// TL;DR
// calling response.send & response.json can be type, NextApiResponse<your_interface_or_type>
interface API_Response {
ok: boolean,
status?: number,
data?: any
}
interface ControllerConstructor {
new (req: NextApiRequest, res: NextApiResponse<API_Response>): IController
}
// instance
interface IController {
req: NextApiRequest,
res: NextApiResponse,
controls: IControlTypes,
exec(): Promise<any>,
setControls(controls: IControlTypes): void
}
// to execute
export type IControlFunction = NextApiHandler<API_Response>
// supported http verbs
type IControlMethods = 'GET' | 'POST' | 'UPDATE' | 'DELETE' | 'PUT' | 'PATCH' | 'OPTIONS'
// available controls
type IControlTypes = {
[methods in IControlMethods]?: IControlFunction;
}
export const Controller: ControllerConstructor = class Controller implements IController {
controls: IControlTypes = {};
// constructor
constructor(public req: NextApiRequest, public res: NextApiResponse<API_Response>){}
// run single controller, [e.g. GET /api/users ]
async exec() {
try{
const { method } = this.req
// get the controller according to http verb | method
const control = this.controls[method as IControlMethods]
if(!control){
// method not supported, end the request
return this.res.status(405).end()
}
// execute the target control
return await control(this.req,this.res)
}catch(e){
// reject the request
return this.res.status(500).json({
ok: false,
status: 500,
data: {}
})
}
}
// set controllers,
// controllers must be set before calling `await this.exec()`
setControls(controls: IControlTypes){
this.controls = controls
}
}
import { Controller, API_Response, IControlFunction } from "./path/to/controller"
import { NextApiRequest, NextApiResponse } from "next"
// these controllers can be at different source file too
const get_handler:IControlFunction = async (req,res) => {
// do some stuff...
res.json({
ok: true,
data: { message: "@sfx_one" }
})
}
const post_handler: IControlFunction = async (req,res) => {
// process some stuff...
res.json({
ok: true,
data: {
subscriber_id: "@sfx_one"
}
})
}
const api_handler = async (req: NextApiRequest,res: NextApiResponse<API_Response>) => {
const controller = new Controller(req,res)
// must set controls first
controller.setControls({
GET: get_handler,
POST: post_handler
})
// do more stuff here...
// call exec
// exec returns a promise, make sure to 'await' it.
await controller.exec()
}
export default api_handler
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment