{"id":24108490,"url":"https://github.com/egorguru/dragonrend","last_synced_at":"2026-05-19T10:35:13.126Z","repository":{"id":47625341,"uuid":"183478347","full_name":"egorguru/dragonrend","owner":"egorguru","description":"Node.js Web Framework","archived":false,"fork":false,"pushed_at":"2021-10-02T21:47:52.000Z","size":146,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-06-27T13:51:34.241Z","etag":null,"topics":["fast","framework","javascript","nodejs","performance","server","web"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"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/egorguru.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}},"created_at":"2019-04-25T17:14:25.000Z","updated_at":"2021-10-02T21:47:54.000Z","dependencies_parsed_at":"2022-09-10T12:10:25.114Z","dependency_job_id":null,"html_url":"https://github.com/egorguru/dragonrend","commit_stats":null,"previous_names":["egorrepnikov/dragonrend"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/egorguru/dragonrend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egorguru%2Fdragonrend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egorguru%2Fdragonrend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egorguru%2Fdragonrend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egorguru%2Fdragonrend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/egorguru","download_url":"https://codeload.github.com/egorguru/dragonrend/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egorguru%2Fdragonrend/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266796900,"owners_count":23985493,"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","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"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":["fast","framework","javascript","nodejs","performance","server","web"],"created_at":"2025-01-10T23:37:55.712Z","updated_at":"2026-05-19T10:35:11.175Z","avatar_url":"https://github.com/egorguru.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/EgorRepnikov/dragonrend.svg?branch=master)](https://travis-ci.org/EgorRepnikov/dragonrend)\n[![version](https://badgen.net/npm/v/dragonrend)](https://www.npmjs.com/package/dragonrend)\n[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/EgorRepnikov/dragonrend/blob/master/LICENSE)\n\n# Dragonrend\nDragonrend is productive and fast Node.js framework for building web applications.\n\nAll these advantages are achieved due to the fact that there is nothing superfluous. You have only what it is needed for creating Backend apps - no more no less. Then you get easy to read code and performance close to bare Node.\n\n# Installation\n```bash\n$ npm install dragonrend\n```\n\n# Usage\nThe framework supports two options for writing code: classic and new way. А new way allows you to create programs due to the extracted functions. This method helps to split the code into blocks that are easier to read. And in the following examples both design options will be shown.\n\n```js\nconst { dragonrend } = require('dragonrend')\n\nconst app = dragonrend()\n\napp.get('/', ctx =\u003e ctx.response.json({ message: 'Hi There' }))\n\napp.start(8080).then(() =\u003e console.log('Server has been started'))\n```\n\n```js\nconst { dragonrend } = require('dragonrend')\n\nconst { GET, START } = dragonrend()\n\nGET('/', ctx =\u003e ctx.response.json({ message: 'Hi There' }))\n\nSTART(8080, () =\u003e console.log('Server has been started'))\n```\n\n# API\n\n## Context\nAll middleware functions and handlers get the `context` object.\nContext contains the `request` and `response` objects by default.\n\n## dragonrend(options)\nThis is builder function, which returns Dragonrend instance.\n\n```js\nconst { dragonrend } = require('dragonrend')\n\nconst app = dragonrend({\n  server: false, // your server instance, default: false\n  https: false, // object with `key` and `cert` like `https.createServer`, default: false\n  http2: false, // true or false, default: false\n  noDelay: true, // disable Nagle algorithm, default: false\n  errorHandler(e, ctx) { // this is default error handler\n    console.log(e)\n    ctx.response.status(500).text('Internal Server Error')\n  },\n  routing: { // default: {}\n    prefix: '/api', // default: ''\n    notFoundHandler(ctx) { // this is default not found handler\n      ctx.response.status(404).text('Not Found')\n    }\n  },\n  autoIncluding: { // default: false\n    rootDir: 'dir', // default: process.cwd() (Node.js process directory)\n    autoIncludeRoutes: true, // this is default value\n    routesDir: 'routes', // this is default value\n    autoIncludeMiddleware: true, // this is default value\n    middlewareDir: 'middleware', // this is default value\n    autoIncludeContentTypeParsers: true, // this is default value\n    contentTypeParsersDir: 'parsers' // this is default value\n  }\n})\n```\n\n## Dragonrend Instance\n`Dragonrend` **inherits** `Router`.\n\n### context(object: Object)\nStores the values you can get from `ctx`.\n\n```js\n// add value\napp.context({\n  someValue: 'mock'\n})\n\napp.get('/path', ctx =\u003e {\n  const { someValue } = ctx // \u003c- and use it\n})\n```\n\n```js\nconst { CONTEXT, GET } = app\n\nCONTEXT({\n  someValue: 'mock'\n})\n\nGET('/path', ctx =\u003e {\n  const { someValue } = ctx // \u003c- and use it\n})\n```\n\n### addContentTypeParser(contentType: String, fn: Function)\nMethod add parser of requests body by content type.\n\n```js\napp.addContentTypeParser('text/plain', body =\u003e {\n  return body.toUpperCase()\n})\n```\n\n```js\nconst { PARSER } = app\n\nPARSER('text/plain', body =\u003e body.toUpperCase())\n```\n\n\u003e **Feature:** Parsers can be added to the application automatically. Read more in the section \"Auto Including\".\n\n### middleware(...fns: Function)\nAdds handler which will called before Router's handler.\n\n```js\n// async/await or return promise\napp.middleware(async ctx =\u003e {\n  // do something\n})\n\napp.middleware(\n  ctx =\u003e {},\n  ctx =\u003e {}\n)\n```\n\n```js\nconst { MIDDLEWARE } = app\n\nMIDDLEWARE(async ctx =\u003e {\n  // do something\n})\n\nMIDDLEWARE(\n  ctx =\u003e {},\n  ctx =\u003e {}\n)\n```\n\nTo break/stop middleware chain you should return `false`.\n\n```js\nconst { MIDDLEWARE } = app\n\nMIDDLEWARE(ctx =\u003e {\n  return false\n})\n\nMIDDLEWARE(async ctx =\u003e {\n  return false\n})\n\nMIDDLEWARE(ctx =\u003e {\n  return Promise.resolve(false)\n})\n```\n\n\u003e **Feature:** Middleware-functions can be added to the application automatically. Read more in the section \"Auto Including\".\n\n### setErrorHandler(fn: Function)\n`fn` should have `(error, ctx)` signature. `error` is an error occurred, `ctx` is context.\n\nSets error handler.\nBy default Dragonrend returns status 500 and body `{\"error\":\"Internal Server Error\"}`.\n\n```js\napp.setErrorHandler((error, ctx) =\u003e {\n  ctx.response.status(500).json({ error: error.message })\n})\n```\n\n```js\nconst { CATCH_ERROR } = app\n\nCATCH_ERROR((error, ctx) =\u003e {\n  ctx.response.status(500).json({ error: error.message })\n})\n```\n\n### start(portOrOptions: Number|Object)\nMethod gets port number or options object like [Net server.listen()](https://nodejs.org/api/net.html#net_server_listen_options_callback). Method returns `Promise`, also it is possible to use callback.\n\n```js\napp.start(8080).then(() =\u003e console.log('Started'))\n// or\napp.start({\n  host: 'localhost',\n  port: 80,\n  exclusive: true\n}).then(() =\u003e console.log('Started'))\n```\n\n```js\nconst { START } = app\n\nSTART(8080, () =\u003e console.log('Started'))\n```\n\n### stop()\nMethod stops server and returns `Promise`, also it is possible to use callback.\n\n```js\ndragonrend.stop().then(() =\u003e console.log('Stopped'))\n```\n\n```js\nconst { STOP } = app\n\nSTOP(() =\u003e console.log('Stopped'))\n```\n\n## Routing\nRouting is performed using [Impetuous](https://github.com/EgorRepnikov/impetuous).\n\n### routing(options: Object)\nGets the object with a `prefix` and `not found handler`, which appends to all routes of that instance of Router. Returns prepared `Router` instance.\n\n```js\nconst router = routing({\n  prefix: '/api',\n  notFoundHandler() {\n    ctx.response.status(404).text('Not Found')\n  }\n})\n```\n\n### NotFound handler\nAlso NotFound-handler can be set via method or function.\n\n```js\nconst router = routing()\n\nrouter.setNotFoundHandler(ctx =\u003e {\n  ctx.response.status(404).text('Not Found')\n})\n```\n\n```js\nconst { NOT_FOUND } = routing()\n\nNOT_FOUND(ctx =\u003e ctx.response.status(404).text('Not Found'))\n```\n\n### Classic Express-like routing\nRouter instance has `get, put, patch, post, delete, head, options` methods with the same arguments `(path: String, ...fn: Function)`.\n\n```js\nconst { routing } = require('dragonrend')\n\nconst router = routing()\n\nrouter.get('/path/:param', async ctx =\u003e {})\n\nrouter.post('/path', ({ request, response }) =\u003e {})\n\nmodule.exports = router\n```\n\n### GET PUT PATCH POST DELETE HEAD OPTIONS (path: String, ...fn: Function)\nThese functions add request handlers.\n\nFor example, a file with routes may look like this:\n\n```js\nconst { routing } = require('dragonrend')\n\nconst { GET, POST } = module.exports = routing()\n\nGET('/path/:param', async (ctx) =\u003e {})\n\nPOST('/path', ({ request, response }) =\u003e {})\n```\n\n### merge(...routers: Router)\nCombines one or more instances of Router.\n\n```js\nconst router1 = routing({ prefix: '/base' })\nconst router2 = routing()\nconst router3 = routing({ prefix: '/api' })\n\nrouter1.merge(router2, router3)\n```\n\n```js\nconst router1 = routing({ prefix: '/base' })\nconst router2 = routing()\nconst router3 = routing({ prefix: '/api' })\n\nconst { MERGE } = router1\n\nMERGE(router2, router3)\n```\n\n### Instance of Router should be added to Dragonrend\n`Dragonrend` inherits `Router`, therefore it has method `merge`.\n\n```js\nconst app = dragonrend()\nconst router = routing()\n// add some handlers to router\napp.merge(router)\n// start server...\n```\n\n```js\nconst { MERGE } = dragonrend()\nconst router = routing()\n\nMERGE(router)\n```\n\n\u003e **Feature:** Routers can be added to the application automatically. Read more in the section \"Auto Including\".\n\n## Request\nRequest objects is added to `context` by default.\n\nFields of Request instance:\n\n| Field | Description |\n|---|---|\n| headers | object, which contains all headers of request |\n| url | url from request |\n| method | request's method |\n| body | parsed request's body |\n| raw | native Node.js's http Request |\n\n```js\napp.middleware(async ctx =\u003e {\n  const { headers, url, method, raw, query } = ctx.request\n  const query = await ctx.request.query() // lazy parsed query\n  const body = await ctx.request.body() // lazy parsed body\n}\n```\n\n## Response\nResponse objects is added to `context` by default.\n\n| Method | Description |\n|---|---|\n| header(key: String, value: String) | Adds header key-value pair to Response |\n| status(statusCode: Number) | Sets custom status code to Response, default value is `200` |\n| json(data: Object) | Sends response with `application/json` body |\n| text(data: String) | Sends response with `text/plain` body |\n| html(data: String) | Sends response with `text/html` body |\n| send(data: String\\|Buffer, contentType: String) | Sends response with custom body |\n| raw | Native Node.js' http Response |\n\n```js\napp.middleware({ response } =\u003e {\n  response\n    .header('x-total-count', '0')\n    .status(201)\n    //\n    .json({ message: 'Hi There' })\n    // or\n    .text('Hi There')\n    // or\n    .html('\u003cp\u003eHi There\u003c/p\u003e')\n    // or\n    .send(imageBuffer, 'image/jpeg')\n})\n```\n\n## Return Response\nIt is possible to return response in middleware function by using `returnable` wrapper-function.\n\n```js\nconst { returnable } = require('dragonrend')\n\napp.middleware(returnable(ctx =\u003e {\n  return {\n    status: 201 // default: 200,\n    headers: { 'content-type': 'text/plain' } // default: {},\n    body: 'body' // default: ''\n  }\n}))\n```\n\n### Response helper-functions\nThese functions set the content type and in the case of JSON stringify it.\n\nFunctions have three call options.\n\n| Option | Description |\n| --- | --- |\n| json(body) | one parameter is the request body |\n| json(status, body) | two parameters are status and body in this order |\n| json(status, headers, body) | three parameters are status, headers and body in this order |\n\n```js\nconst { dragonrend, returnable, json, html, text } = require('dragonrend')\n\nconst { GET } = dragonrend()\n\nGET('/json', returnable(ctx =\u003e json({ message: 'Hi There' })))\n\nGET('/html', returnable(ctx =\u003e html(201, '\u003cp\u003eHi There\u003c/p\u003e')))\n\nGET('/text', returnable(ctx =\u003e text(201, { 'header': 'value' }, 'Hi There')))\n```\n\n## Auto Including\nDragonrend supports auto including of Middleware-functions, Routers and Content Type Parsers. You should follow some rules for this functionality to work.\n\nThis feature is disabled by default. You can enable it:\n\n```js\nconst app = dragonrend({\n  autoIncluding: true\n})\n// or with options\nconst app = dragonrend({\n  autoIncluding: {\n    // options\n  }\n})\n```\n\n- Files must be in specific directories at the root of project.\n  - Middleware-functions in `middleware` directory.\n  - Routers Instances in `routes` directory.\n  - Content Type Parsers in `parsers` directory.\n- The root directory is the directory that contains the file that is launched very first, i.e. directory of the Node.js process. If you start project with npm script (like `npm run start`) and all JS files are in `src` directory and main file is `src/index.js`, then root is `../src` and Auto Including will not work. In this case, it can be customized.\n\n```js\n// There are default values of options\nconst app = dragonrend({\n  autoIncluding: {\n    routesDir: 'routes',\n    autoIncludeMiddleware: true,\n    middlewareDir: 'middleware',\n    autoIncludeContentTypeParsers: true,\n    contentTypeParsersDir: 'parsers',\n    rootDir: process.cwd()\n  }\n})\n```\n\nIf you use `src` directory for example as root of application, then you should set that args:\n\n```js\nconst app = dragonrend({\n  autoIncluding: {\n    rootDir: __dirname\n  }\n})\n```\n\n### Parsers\nModules should export an object like that:\n\n```js\nmodule.exports = {\n  contentType: 'text/plain',\n  parse(body) {\n    // do something\n    return body\n  }\n}\n```\n\n### Middleware\nModules should export a function.\n\n```js\nmodule.exports = ctx =\u003e {\n  // do something\n}\n```\n\n### Router\nRouter module should export `Router` instance.\n\n```js\nconst router = routing()\n\nmodule.exports = router\n```\n\n```js\nconst { GET } = module.exports = routing()\n```\n\n# Example\nYou can find an example of using the framework by [link](https://github.com/EgorRepnikov/dragonrend-example). This is a simple Blog implementation with Articles API and JWT-authentication.\n\nAlso there is a [Profile](https://github.com/EgorRepnikov/artaeum/tree/master/profile) microservice of a simple social network [Artaeum](https://github.com/EgorRepnikov/artaeum).\n\n# Author\n**Egor Repnikov** - [GitHub](https://github.com/EgorRepnikov)\n\n# License\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegorguru%2Fdragonrend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegorguru%2Fdragonrend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegorguru%2Fdragonrend/lists"}