A simple, easy to use, scoped web server, with async linear middlewares and no callbacks.
It is an example:
- To show that callbacks are not needed with promise/async/await.
- To use middlewares in a linear way instead of stacked way which is insecure.
For the stacked middleware model will carry response back to the top most so called middleware pushed, where every middleware can access to the body returned.
- To pass some vairiables through middlewares and to the final handler.
import { Aex, Router } from "@aex/core";
const aex = new Aex();
const router = new Router(aex);
// Simple string route
router.get("/", async (req, res, scope) => {
// request processing time started
console.log(scope.time.stated);
// processing time passed
console.log(scope.time.passed);
res.end("Hello Aex!");
});
// Route Array
router.get(["/user/home", "/user/profile"], async (req, res, scope) => {
// request processing time started
console.log(scope.time.stated);
// processing time passed
console.log(scope.time.passed);
res.end("Hello Aex!");
});
aex.use(router.toMiddleware());
const port = 3000;
const host = "localhost";
aex.start(port, host).then();npm i @aex/coreor
yarn add @aex/coreconst aex = new Aex();const router = new Router();router.get("/", async (req, res, scope) => {
// request processing time started
console.log(scope.time.stated);
// processing time passed
console.log(scope.time.passed);
res.end("Hello Aex!");
});aex.use(router.toMiddleware());const port = 3000;
const host = "localhost";
const server = await aex.start(port, host);
// server === aex.server- Create a
WebSocketServerinstance
const aex = new Aex();
const server = await aex.start();
const ws = new WebSocketServer(server);- Get handler for one websocket connection
ws.on(WebSocketServer.ENTER, handler => {
// process/here
});- Listen on user-customized events
ws.on(WebSocketServer.ENTER, handler => {
handler.on("event-name", data => {
// data.message = "Hello world!"
});
});- Send message to browser / client
ws.on(WebSocketServer.ENTER, handler => {
handler.send("event-name", { key: "value" });
});- New browser/client WebSocket object
const wsc: WebSocket = new WebSocket("ws://localhost:3000/path");
wsc.on("open", function open() {
wsc.send("");
});- Listen on user-customized events
ws.on("new-message", () => {
// process/here
});- Sending ws message in browser/client
const wsc: WebSocket = new WebSocket("ws://localhost:3000/path");
wsc.on("open", function open() {
wsc.send(
JSON.stringify({
event: "event-name",
data: {
message: "Hello world!"
}
})
);
});- Use websocket middlewares
ws.use(async (req, ws, scope) => {
// return false
});Global middlewares are effective all over the http request process.
They can be added by aex.use function.
aex.use(async (req, res, scope) => {
// process 1
// return false
});
aex.use(async (req, res, scope) => {
// process 2
// return false
});
// ...
aex.use(async (req, res, scope) => {
// process N
// return false
});Return
falsein middlewares will cancel the whole http request processing
It normally happens after ares.end
Handler specific middlewares are effective only to the specific handler.
They can be optionally added to the handler option via the optional attribute middlewares.
the middlewares attribute is an array of async functions of IAsyncMiddleware.
so we can simply define handler specific middlewares as follows:
router.get(
"/",
async (req, res, scope) => {
res.end("Hello world!");
},
[
async (req, res, scope) => {
// process 1
// return false
},
async (req, res, scope) => {
// process 2
// return false
},
// ...,
async (req, res, scope) => {
// process N
// return false
}
]
);Websocket middlewares are of the same to the above middlewares except that the parameters are of different.
type IWebSocketAsyncMiddleware = (
req: Request,
socket: WebSocket,
scope?: Scope
) => Promise<boolean | undefined | null | void>;The Websocket Middlewares are defined as IWebSocketAsyncMiddleware, they pass three parameters:
- the http request
- the websocket object
- the scope object
THe middlewares can stop websocket from further execution by return false
The node system http.Server.
Accessable through aex.server.
const aex = new Aex();
const server = await aex.start();
expect(server === aex.server).toBeTruthy();
server.close();Aex provides scoped data for global and local usage.
A scope object is passed by middlewares and handlers right after req, res as the third parameter.
It is defined in IAsyncMiddleware as the following:
async (req, res, scope) => {
// process N
// return false
};the scope variable has three native attributes: time, outer, inner.
The time attribute contains the started time and passed time of requests.
The outer attribute is to store general or global data.
The inner attribute is to store specific or local data.
- Get the requesting time
scope.time.started;
// 2019-12-12T09:01:49.543Z- Get the passed time
scope.time.passed;
// 2019-12-12T09:01:49.543ZThe outer and innervariables are objects used to store data for different purposes.
You can simply assign them a new attribute with data;
scope.inner.a = 100;
scope.outer.a = 120;// scope.outer = {}; // Wrong operation!
// scope.inner = {}; // Wrong operation!
// scope.time = {}; // Wrong operation!
// scope.time.started = {}; // Wrong operation!
// scope.time.passed = {}; // Wrong operation!Aex provide a way for express middlewares to be translated into Aex middlewares.
You need just a simple call to toAsyncMiddleware to generate Aex's async middleware.
const oldMiddleware = (_req: any, _res: any, next: any) => {
// ...
next();
};
const pOld = toAsyncMiddleware(oldMiddleware);
aex.use(pOld);You should be cautious to use express middlewares. Full testing is appreciated.