{"id":15068336,"url":"https://github.com/egomobile/node-http-server","last_synced_at":"2025-10-05T06:30:49.373Z","repository":{"id":142756828,"uuid":"613823866","full_name":"egomobile/node-http-server","owner":"egomobile","description":"Very fast alternative to Express.js, with simple routing and middleware support for Node.js","archived":true,"fork":false,"pushed_at":"2024-02-24T16:51:05.000Z","size":4515,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-15T18:37:55.715Z","etag":null,"topics":["backend","connect","controllers","express","express-js","express-middleware","expressjs","http","http-server","javascript","js","middleware","mvc","mvc-pattern","node","node-js","nodejs","server","ts","typescript"],"latest_commit_sha":null,"homepage":"https://egomobile.github.io/node-http-server/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/egomobile.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2023-03-14T10:46:29.000Z","updated_at":"2024-05-22T17:48:18.000Z","dependencies_parsed_at":"2024-06-20T23:29:26.686Z","dependency_job_id":null,"html_url":"https://github.com/egomobile/node-http-server","commit_stats":{"total_commits":284,"total_committers":2,"mean_commits":142.0,"dds":0.1161971830985915,"last_synced_commit":"8ee607154277c1ea87f5c6bfa97a16002c3c1f3e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egomobile%2Fnode-http-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egomobile%2Fnode-http-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egomobile%2Fnode-http-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egomobile%2Fnode-http-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/egomobile","download_url":"https://codeload.github.com/egomobile/node-http-server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235370461,"owners_count":18979093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["backend","connect","controllers","express","express-js","express-middleware","expressjs","http","http-server","javascript","js","middleware","mvc","mvc-pattern","node","node-js","nodejs","server","ts","typescript"],"created_at":"2024-09-25T01:34:10.969Z","updated_at":"2025-10-05T06:30:43.955Z","avatar_url":"https://github.com/egomobile.png","language":"TypeScript","readme":"[![npm](https://img.shields.io/npm/v/@egomobile/http-server.svg)](https://www.npmjs.com/package/@egomobile/http-server)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/egomobile/node-http-server/pulls)\n\n# @egomobile/http-server\n\n\u003e A very fast alternative HTTP server to Express, with simple routing and middleware support, that is compatible with [Node.js 18](https://nodejs.org/en/blog/release/v18.0.0/) or later.\n\n\u003ca name=\"toc\"\u003e\u003c/a\u003e\n\n## Table of contents\n\n- [Install](#install)\n- [Usage](#usage)\n  - [Quick example](#quick-example)\n  - [Middlewares](#middlewares)\n  - [Controllers](#controllers)\n  - [Error handling](#error-handling)\n    - [Pretty error pages](#pretty-error-pages)\n  - [Testing](#testing)\n- [Benchmarks](#benchmarks)\n- [Credits](#credits)\n- [Documentation](#documentation)\n- [See also](#see-also)\n\n\u003ca name=\"install\"\u003e\u003c/a\u003e\n\n## Install [\u003ca href=\"#toc\"\u003e↑\u003c/a\u003e]\n\nExecute the following command from your project folder, where your\n`package.json` file is stored:\n\n```bash\nnpm install --save @egomobile/http-server\n```\n\nIf you want to lookup types, also install the Node Types:\n\n```bash\nnpm install --save-dev @types/node\n```\n\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n\n## Usage [\u003ca href=\"#toc\"\u003e↑\u003c/a\u003e]\n\n\u003ca name=\"quick-example\"\u003e\u003c/a\u003e\n\n### Quick example [\u003ca href=\"#usage\"\u003e↑\u003c/a\u003e]\n\n```typescript\nimport createServer, { buffer, params, query } from \"@egomobile/http-server\";\n\nasync function main() {\n  const app = createServer();\n\n  // POST request for / route\n  // that uses the middleware buffer(), which loads the\n  // whole request body with a limit of 128 MB by default\n  // and writes the data to 'body' prop of 'request' object\n  // as Buffer\n  app.post(\"/\", [buffer()], async (request, response) =\u003e {\n    const name: string = request.body!.toString(\"utf8\");\n\n    response.write(\"Hello: \" + name);\n    // no response.end() is required here\n  });\n\n  // parameters require a special path validator here\n  // s. https://github.com/lukeed/regexparam\n  // for more information about the string format\n  app.get(params(\"/foo/:bar/baz\"), async (request, response) =\u003e {\n    response.write(\"BAR: \" + request.params!.bar);\n  });\n\n  // parse query parameters from URL\n  // and write them to 'query' prop of 'request' object\n  app.get(\"/foo\", [query()], async (request, response) =\u003e {\n    // request.query =\u003e https://nodejs.org/api/url.html#class-urlsearchparams\n\n    response.write(\" BAR: \" + request.query!.get(\"bar\"));\n    response.write(\" BAZ: \" + request.query!.get(\"baz\"));\n  });\n\n  await app.listen();\n  console.log(`Server now running on port ${app.port} ...`);\n}\n\nmain().catch(console.error);\n```\n\n\u003ca name=\"middlewares\"\u003e\u003c/a\u003e\n\n### Middlewares [\u003ca href=\"#usage\"\u003e↑\u003c/a\u003e]\n\nTo enhance the functionality of your handlers, you can setup global or route\nspecific middlewares.\n\nFor more details, have a look\n[at the wiki page](https://github.com/egomobile/node-http-server/wiki/Middlewares).\n\n\u003ca name=\"controllers\"\u003e\u003c/a\u003e\n\n### Controllers [\u003ca href=\"#usage\"\u003e↑\u003c/a\u003e]\n\nThe module provides tools, like\n[decorators](https://www.typescriptlang.org/docs/handbook/decorators.html),\n[functions](https://www.typescriptlang.org/docs/handbook/functions.html) and\n[classes](https://www.typescriptlang.org/docs/handbook/classes.html), that helps\nto setup routes and their behavior on a quite simple and high level.\n\nHave a look\n[at the wiki page](https://github.com/egomobile/node-http-server/wiki/Controllers)\nfor detailed information.\n\n\u003ca name=\"error-handling\"\u003e\u003c/a\u003e\n\n### Error handling [\u003ca href=\"#usage\"\u003e↑\u003c/a\u003e]\n\n```typescript\nimport createServer from \"@egomobile/http-server\";\n\nasync function main() {\n  // ...\n\n  // custom error handler\n  app.setErrorHandler(async (error, request, response) =\u003e {\n    const errorMessage = Buffer.from(\"SERVER ERROR: \" + String(error), \"utf8\");\n\n    if (!response.headersSend) {\n      response.writeHead(400, {\n        \"Content-Length\": String(errorMessage.length),\n      });\n    }\n\n    response.write(errorMessage);\n    response.end();\n  });\n\n  // custom 404 handler\n  app.setNotFoundHandler(async (request, response) =\u003e {\n    const notFoundMessage = Buffer.from(`${request.url} not found!`, \"utf8\");\n\n    if (!response.headersSend) {\n      response.writeHead(404, {\n        \"Content-Length\": String(notFoundMessage.length),\n      });\n    }\n\n    response.write(notFoundMessage);\n    response.end();\n  });\n\n  app.get(\"/\", async (request, response) =\u003e {\n    throw new Error(\"Something went wrong!\");\n  });\n\n  // ...\n}\n\nmain().catch(console.error);\n```\n\n\u003ca name=\"pretty-error-pages\"\u003e\u003c/a\u003e\n\n#### Pretty error pages [\u003ca href=\"#error-handling\"\u003e↑\u003c/a\u003e]\n\nA nice example is, to use [Youch!](https://github.com/poppinss/youch) by [Poppinss](https://github.com/poppinss).\n\nIt prints pretty error pages in the browser:\n\n```typescript\nimport createServer, { prettyErrors } from \"@egomobile/http-server\";\nimport youch from \"youch\";\n\nasync function main() {\n  // ...\n\n  app.setErrorHandler(async (error, request, response) =\u003e {\n    const html = Buffer.from(await new youch(error, request).toHTML(), \"utf8\");\n\n    if (!response.headersSent) {\n      response.writeHead(500, {\n        \"Content-Type\": \"text/html; charset=UTF-8\",\n        \"Content-Length\": String(html.length),\n      });\n    }\n\n    response.end(html);\n  });\n\n  app.get(\"/\", async (request, response) =\u003e {\n    throw new Error(\"Oops! Something went wrong!\");\n  });\n\n  // ...\n}\n\nmain().catch(console.error);\n```\n\nA possible result could be:\n\n\u003ckbd\u003e\u003cimg src=\"./assets/screenshot.png\" /\u003e\u003c/kbd\u003e\n\n\u003ca name=\"testing\"\u003e\u003c/a\u003e\n\n## Testing [\u003ca href=\"#usage\"\u003e↑\u003c/a\u003e]\n\nWith decorators [@Describe()](https://egomobile.github.io/node-http-server/functions/Describe.html) and [@It()](https://egomobile.github.io/node-http-server/functions/It.html), you can write automatic (unit-)tests, realized by any framework you want.\n\nThis example shows, how to implement tests with [SuperTest](https://github.com/ladjs/supertest) (if you want to see a more detailed description of this feature, you can visit the [wiki page](https://github.com/egomobile/node-http-server/wiki/Testing)):\n\n### Controller [\u003ca href=\"#testing\"\u003e↑\u003c/a\u003e]\n\n```typescript\nimport {\n  Controller,\n  ControllerBase,\n  Describe,\n  GET,\n  IHttpRequest,\n  IHttpResponse,\n  It,\n} from \"@egomobile/http-server\";\n\n@Controller()\n@Describe(\"My controller\")\nexport default class MyController extends ControllerBase {\n  @GET(\"/foo/:bar\")\n  @It(\n    \"should return '{{body}}' in body with status {{status}} when submitting parameter {{parameter:bar}}\",\n    {\n      expectations: {\n        body: \"BUZZ\",\n        status: 202,\n      },\n      parameters: {\n        bar: \"buzz\",\n      },\n    }\n  )\n  async index(request: IHttpRequest, response: IHttpResponse) {\n    response.writeHead(202);\n    response.write(request.params!.bar.toUpperCase());\n  }\n}\n```\n\n### Initialization [\u003ca href=\"#testing\"\u003e↑\u003c/a\u003e]\n\n```typescript\nimport assert from \"assert\";\nimport supertest from \"supertest\";\nimport { createServer } from \"@egomobile/http-server\";\n\nconst app = createServer();\n\n// event, that is executed, if a test is requested\napp.on(\"test\", async (context) =\u003e {\n  const {\n    body,\n    description,\n    escapedRoute,\n    expectations,\n    group,\n    headers,\n    httpMethod,\n    server,\n  } = context;\n\n  try {\n    process.stdout.write(`Running test [${group}] '${description}' ... `);\n\n    // prepare request ...\n    // HTTP method ...\n    let request = supertest(server)[httpMethod](escapedRoute);\n    // request headers ...\n    for (const [headerName, headerValue] of Object.entries(headers)) {\n      request = request.set(headerName, headerValue);\n    }\n\n    // send it\n    const response = await request.send(body);\n\n    assert.strictEqual(response.statusCode, expectations.status);\n\n    // maybe some more code checking headers and\n    // body data from `expectations` ...\n\n    process.stdout.write(`✅\\n`);\n  } catch (error) {\n    process.stdout.write(`❌: ${error}\\n`);\n  }\n});\n\n// run tests\nawait app.test();\n\n// alternative:\n//\n// if you set `EGO_RUN_SETUP` to a truthy value like `1`\n// the server does not start listening, instead it simply\n// runs `app.test()`\n//\n// await app.listen();\n```\n\n\u003ca name=\"benchmarks\"\u003e\u003c/a\u003e\n\n## Benchmarks [\u003ca href=\"#toc\"\u003e↑\u003c/a\u003e]\n\n| \u0026nbsp;                   |  `Express`  | `fastify` | `polka` | `@egomobile/http-server` |\n| ------------------------ | :---------: | :-------: | :-----: | :----------------------: |\n| `Express`                |      -      |    93%    |   39%   |          30% 🐌          |\n| `fastify`                |    107%     |     -     |   43%   |          32% 🐢          |\n| `polka`                  |    256%     |   238%    |    -    |          76% 🐇          |\n| `@egomobile/http-server` | 337% 🚀🚀🚀 | 314% 🚀🚀 | 132% 🚀 |            -             |\n\nThe following benchmarks were made with [wrk](https://github.com/wg/wrk) on the following machine, running [Node v16.13.2](https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V16.md#16.13.2):\n\nMachine:\n\n- MacBook Pro (16\", 2021)\n- CPU: Apple M1 Max\n- Memory: 64 GB\n- OS: MacOS 12.1\n\nCommand: `wrk -t8 -c100 -d30s http://localhost:3000/user/123`\n\n```\nExpress:\n=============\nRunning 30s test @ http://localhost:3000/user/123\n  8 threads and 100 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency     3.56ms  674.79us  14.59ms   90.47%\n    Req/Sec     3.39k   224.41     5.11k    75.04%\n  809164 requests in 30.03s, 118.84MB read\nRequests/sec:  26947.30\nTransfer/sec:      3.96MB\n\n\nFastify:\n=============\nRunning 30s test @ http://localhost:3000/user/123\n  8 threads and 100 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency     3.32ms    0.95ms  19.41ms   85.25%\n    Req/Sec     3.64k   280.76     4.87k    76.38%\n  869871 requests in 30.03s, 142.69MB read\nRequests/sec:  28971.44\nTransfer/sec:      4.75MB\n\n\nPolka:\n===========\nRunning 30s test @ http://localhost:3000/user/123\n  8 threads and 100 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency     1.39ms  289.29us  13.20ms   91.15%\n    Req/Sec     8.66k     1.26k   10.67k    59.55%\n  2074873 requests in 30.10s, 259.22MB read\nRequests/sec:  68930.81\nTransfer/sec:      8.61MB\n\n\n@egomobile/http-server:\n============================\nRunning 30s test @ http://localhost:3000/user/123\n  8 threads and 100 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency     1.05ms  220.64us  13.11ms   85.16%\n    Req/Sec    11.44k     1.39k   18.48k    81.16%\n  2737095 requests in 30.10s, 341.95MB read\nRequests/sec:  90922.13\nTransfer/sec:     11.36MB\n```\n\n[Here](./benchmarks) is the test code, used recording the benchmarks.\n\n\u003ca name=\"credits\"\u003e\u003c/a\u003e\n\n## Credits [\u003ca href=\"#toc\"\u003e↑\u003c/a\u003e]\n\nThe module makes use of:\n\n- [Ajv](https://ajv.js.org/)\n- [Filtrex](https://github.com/m93a/filtrex) by [Michal Grňo](https://github.com/m93a)\n- [joi](https://joi.dev/) by [Sideway Inc.](https://github.com/sideway)\n- [js-yaml](https://github.com/nodeca/js-yaml) by\n  [Nodeca](https://github.com/nodeca)\n- [minimatch](https://github.com/isaacs/minimatch) by\n  [isaacs](https://github.com/isaacs)\n- [regexparam](https://github.com/lukeed/regexparam) by\n  [Luke Edwards](https://github.com/lukeed)\n- [Swagger UI](https://github.com/swagger-api/swagger-ui) and\n  [@open-api](https://github.com/kogosoftwarellc/open-api)\n\n\u003ca name=\"documentation\"\u003e\u003c/a\u003e\n\n## Documentation [\u003ca href=\"#toc\"\u003e↑\u003c/a\u003e]\n\nThe API documentation can be found\n[here](https://egomobile.github.io/node-http-server/).\n\n\u003ca name=\"see-also\"\u003e\u003c/a\u003e\n\n## See also [\u003ca href=\"#toc\"\u003e↑\u003c/a\u003e]\n\n- [@egomobile/api-utils](https://github.com/egomobile/node-api-utils) - Extensions for this module, helping realizing REST APIs\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegomobile%2Fnode-http-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegomobile%2Fnode-http-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegomobile%2Fnode-http-server/lists"}