{"id":19044649,"url":"https://github.com/bubao/aex","last_synced_at":"2026-03-01T13:03:13.997Z","repository":{"id":207029353,"uuid":"247404424","full_name":"bubao/aex","owner":"bubao","description":"A simple, async, scoped web server, with async middlewares and no more callbacks.","archived":false,"fork":false,"pushed_at":"2019-12-26T15:44:29.000Z","size":542,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-11-12T13:03:06.035Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://t1bao.com/","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bubao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-15T04:59:35.000Z","updated_at":"2021-06-03T13:19:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"56c1966d-e275-45f2-8860-ea6d730aec74","html_url":"https://github.com/bubao/aex","commit_stats":null,"previous_names":["bubao/aex"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/bubao/aex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bubao%2Faex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bubao%2Faex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bubao%2Faex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bubao%2Faex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bubao","download_url":"https://codeload.github.com/bubao/aex/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bubao%2Faex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29969700,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T12:56:10.327Z","status":"ssl_error","status_checked_at":"2026-03-01T12:55:24.744Z","response_time":124,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T22:46:57.004Z","updated_at":"2026-03-01T13:03:13.936Z","avatar_url":"https://github.com/bubao.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.com/calidion/aex.svg?branch=master)](https://travis-ci.com/calidion/aex)\n[![Coverage Status](https://coveralls.io/repos/github/calidion/aex/badge.svg?branch=master)](https://coveralls.io/github/calidion/aex?branch=master)\n[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)\n\n# AEX\n\nA simple, easy to use, scoped web server, with async linear middlewares and no callbacks.\n\nIt is an example:\n\n1. To show that callbacks are not needed with promise/async/await.\n2. To use middlewares in a linear way instead of stacked way which is insecure.\n   \u003e 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.\n3. To pass some vairiables through middlewares and to the final handler.\n\n# A simple example\n\n```ts\nimport { Aex, Router } from \"@aex/core\";\n\nconst aex = new Aex();\nconst router = new Router(aex);\n\n// Simple string route\nrouter.get(\"/\", async (req, res, scope) =\u003e {\n  // request processing time started\n  console.log(scope.time.stated);\n  // processing time passed\n  console.log(scope.time.passed);\n  res.end(\"Hello Aex!\");\n});\n\n// Route Array\nrouter.get([\"/user/home\", \"/user/profile\"], async (req, res, scope) =\u003e {\n  // request processing time started\n  console.log(scope.time.stated);\n  // processing time passed\n  console.log(scope.time.passed);\n  res.end(\"Hello Aex!\");\n});\n\naex.use(router.toMiddleware());\n\nconst port = 3000;\nconst host = \"localhost\";\naex.start(port, host).then();\n```\n\n# Install\n\n```sh\nnpm i @aex/core\n```\n\nor\n\n```sh\nyarn add @aex/core\n```\n\n# Usage\n\n## 1. Create an Aex instance\n\n```ts\nconst aex = new Aex();\n```\n\n## 2. Create a Router\n\n```ts\nconst router = new Router();\n```\n\n## 2. Setup the option for handler\n\n```ts\nrouter.get(\"/\", async (req, res, scope) =\u003e {\n  // request processing time started\n  console.log(scope.time.stated);\n  // processing time passed\n  console.log(scope.time.passed);\n  res.end(\"Hello Aex!\");\n});\n```\n\n## 3. Use router as an middleware\n\n```ts\naex.use(router.toMiddleware());\n```\n\n## 4. Start the server\n\n```ts\nconst port = 3000;\nconst host = \"localhost\";\nconst server = await aex.start(port, host);\n// server === aex.server\n```\n\n# Websocket support\n\n## Simple example\n\n1. Create a `WebSocketServer` instance\n\n```ts\nconst aex = new Aex();\nconst server = await aex.start();\nconst ws = new WebSocketServer(server);\n```\n\n2. Get handler for one websocket connection\n\n```ts\nws.on(WebSocketServer.ENTER, handler =\u003e {\n  // process/here\n});\n```\n\n3. Listen on user-customized events\n\n```ts\nws.on(WebSocketServer.ENTER, handler =\u003e {\n  handler.on(\"event-name\", data =\u003e {\n    // data.message = \"Hello world!\"\n  });\n});\n```\n\n4. Send message to browser / client\n\n```ts\nws.on(WebSocketServer.ENTER, handler =\u003e {\n  handler.send(\"event-name\", { key: \"value\" });\n});\n```\n\n5. New browser/client WebSocket object\n\n```ts\nconst wsc: WebSocket = new WebSocket(\"ws://localhost:3000/path\");\nwsc.on(\"open\", function open() {\n  wsc.send(\"\");\n});\n```\n\n6. Listen on user-customized events\n\n```ts\nws.on(\"new-message\", () =\u003e {\n  // process/here\n});\n```\n\n7. Sending ws message in browser/client\n\n```ts\nconst wsc: WebSocket = new WebSocket(\"ws://localhost:3000/path\");\nwsc.on(\"open\", function open() {\n  wsc.send(\n    JSON.stringify({\n      event: \"event-name\",\n      data: {\n        message: \"Hello world!\"\n      }\n    })\n  );\n});\n```\n\n8. Use websocket middlewares\n\n```ts\nws.use(async (req, ws, scope) =\u003e {\n  // return false\n});\n````\n\n# Middlewares\n\n## Global middlewares\n\nGlobal middlewares are effective all over the http request process.\n\nThey can be added by `aex.use` function.\n\n```ts\naex.use(async (req, res, scope) =\u003e {\n  // process 1\n  // return false\n});\n\naex.use(async (req, res, scope) =\u003e {\n  // process 2\n  // return false\n});\n\n// ...\n\naex.use(async (req, res, scope) =\u003e {\n  // process N\n  // return false\n});\n```\n\n\u003e Return `false` in middlewares will cancel the whole http request processing  \n\u003e It normally happens after a `res.end`\n\n## Handler specific middlewares\n\nHandler specific middlewares are effective only to the specific handler.\n\nThey can be optionally added to the handler option via the optional attribute `middlewares`.\n\nthe `middlewares` attribute is an array of async functions of `IAsyncMiddleware`.\n\nso we can simply define handler specific middlewares as follows:\n\n```ts\nrouter.get(\n  \"/\",\n  async (req, res, scope) =\u003e {\n    res.end(\"Hello world!\");\n  },\n  [\n    async (req, res, scope) =\u003e {\n      // process 1\n      // return false\n    },\n    async (req, res, scope) =\u003e {\n      // process 2\n      // return false\n    },\n    // ...,\n    async (req, res, scope) =\u003e {\n      // process N\n      // return false\n    }\n  ]\n);\n```\n\n## Websocket middlewares\n\nWebsocket middlewares are of the same to the above middlewares except that the parameters are of different.\n\n```ts\ntype IWebSocketAsyncMiddleware = (\n  req: Request,\n  socket: WebSocket,\n  scope?: Scope\n) =\u003e Promise\u003cboolean | undefined | null | void\u003e;\n```\n\nThe Websocket Middlewares are defined as `IWebSocketAsyncMiddleware`, they pass three parameters:\n\n1. the http request\n2. the websocket object\n3. the scope object\n\nTHe middlewares can stop websocket from further execution by return `false`\n\n# Accessable members\n\n## server\n\nThe node system `http.Server`.\n\nAccessable through `aex.server`.\n\n```ts\nconst aex = new Aex();\nconst server = await aex.start();\nexpect(server === aex.server).toBeTruthy();\nserver.close();\n```\n\n# Scope\n\nAex provides scoped data for global and local usage.\n\nA scope object is passed by middlewares and handlers right after `req`, `res` as the third parameter.\n\nIt is defined in `IAsyncMiddleware` as the following:\n\n```ts\nasync (req, res, scope) =\u003e {\n  // process N\n  // return false\n};\n```\n\nthe `scope` variable has three native attributes: `time`, `outer`, `inner`.\n\nThe `time` attribute contains the started time and passed time of requests.\nThe `outer` attribute is to store general or global data.\nThe `inner` attribute is to store specific or local data.\n\n## `time`\n\n1. Get the requesting time\n\n```ts\nscope.time.started;\n// 2019-12-12T09:01:49.543Z\n```\n\n2.  Get the passed time\n\n```ts\nscope.time.passed;\n// 2019-12-12T09:01:49.543Z\n```\n\n## `outer` and `inner`\n\nThe `outer` and `inner`variables are objects used to store data for different purposes.\n\nYou can simply assign them a new attribute with data;\n\n```ts\nscope.inner.a = 100;\nscope.outer.a = 120;\n```\n\n## all these build-in attribute are readonly\n\n```ts\n// scope.outer = {};  // Wrong operation!\n// scope.inner = {};   // Wrong operation!\n// scope.time = {};    // Wrong operation!\n// scope.time.started = {};  // Wrong operation!\n// scope.time.passed = {};   // Wrong operation!\n```\n\n# Use middlewares from expressjs\n\nAex provide a way for express middlewares to be translated into Aex middlewares.\n\nYou need just a simple call to `toAsyncMiddleware` to generate Aex's async middleware.\n\n```ts\nconst oldMiddleware = (_req: any, _res: any, next: any) =\u003e {\n  // ...\n  next();\n};\n\nconst pOld = toAsyncMiddleware(oldMiddleware);\naex.use(pOld);\n```\n\n\u003e You should be cautious to use express middlewares.\n\u003e Full testing is appreciated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbubao%2Faex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbubao%2Faex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbubao%2Faex/lists"}