rjweb-server
Version:
Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS
137 lines (136 loc) • 4.39 kB
JavaScript
import { object } from "@rjweb/utils";
export default class Validator {
/**
* Create a new Validator
* @example
* ```
* import { Server, Channel } from "rjweb-server"
* import { Runtime } from "@rjweb/runtime-generic"
* import { network, number } from "@rjweb/utils"
*
* const echo = new Channel<string>()
*
* const server = new Server(Runtime, {
* port: 8000
* })
*
* const authorize = new server.Validator<{ password: string }>()
* .http((ctr, end, data) => {
* if (!ctr.headers.has('authorization')) return end(ctr.status(ctr.$status.BAD_REQUEST).print('Authorization Required'))
* if (ctr.headers.get('authorization') !== data.password) return end(ctr.status(ctr.$status.UNAUTHORIZED).print('Authorization Required'))
* })
*
* const authorizeLast = new server.Validator<{ allowedIP: network.IPAddress }>()
* .extend(authorize)
* .context<{
* random: number
* }>()
* .http((ctr, end, data) => {
* if (!ctr.client.ip.equals(data.allowedIP)) return end(ctr.status(ctr.$status.UNAUTHORIZED).print('Invalid IP'))
*
* ctr["@"].random = number.generate(0, 100)
* })
*
* server.path('/', (path) => path
* .ws('/echo', (ws) => ws
* .validate(authorize.use({ password: '123' }))
* .onConnect((ctr) => {
* ctr.subscribe(echo)
* })
* .onMessage((ctr) => {
* echo.send(ctr.rawMessage()) // will send the message to all subscribed sockets
* })
* )
* .http('GET', '/last-echo', (http) => http
* .validate(authorizeLast.use({ password: '123', allowedIP: new network.IPAddress('127.1') }))
* .onRequest((ctr) => {
* return ctr.print(
* echo.last() +
* `\n${ctr["@"].random}`
* )
* })
* )
* )
*
* server.start().then(() => console.log('Server Started!'))
* ```
* @since 9.0.0
*/ constructor() {
this.openApi = {};
this.openApiFn = null;
this.listeners = {
httpRequest: [],
wsOpen: [],
wsMessage: [],
wsClose: []
};
}
/**
* Add OpenAPI Documentation to all Endpoints using this Validator
* @since 9.0.0
*/ document(item) {
if (typeof item !== 'function')
this.openApi = object.deepMerge(this.openApi, item);
else
this.openApiFn = item;
return this;
}
/**
* Add context variables to the validator, typescript only
* @since 9.0.0
*/ context() {
return this;
}
/**
* Extend on another validator
* @since 9.0.0
*/ extend(validator) {
this.listeners.httpRequest.unshift(...validator.listeners.httpRequest);
this.listeners.wsOpen.unshift(...validator.listeners.wsOpen);
this.listeners.wsMessage.unshift(...validator.listeners.wsMessage);
this.listeners.wsClose.unshift(...validator.listeners.wsClose);
this.openApi = object.deepMerge(this.openApi, validator.openApi);
const openApiFn = this.openApiFn;
if (validator.openApiFn)
this.openApiFn = (data) => object.deepMerge(openApiFn?.(data) ?? {}, validator.openApiFn?.(data) ?? {});
return this;
}
/**
* Add a validation step for an http event
* @since 9.0.0
*/ httpRequest(handler) {
this.listeners.httpRequest.push(handler);
return this;
}
/**
* Add a validation step for a websocket open event
* @since 9.0.0
*/ wsOpen(handler) {
this.listeners.wsOpen.push(handler);
return this;
}
/**
* Add a validation step for a websocket message event
* @since 9.0.0
*/ wsMessage(handler) {
this.listeners.wsMessage.push(handler);
return this;
}
/**
* Add a validation step for a websocket close event
* @since 9.0.0
*/ wsClose(handler) {
this.listeners.wsClose.push(handler);
return this;
}
/**
* Use the Validator
* @since 9.0.0
*/ use(data) {
return {
data,
listeners: this.listeners,
openApi: object.deepMerge(this.openApi, this.openApiFn?.(data) ?? {}),
};
}
}