{"id":25711301,"url":"https://github.com/lucasmendesl/express-decorator-router","last_synced_at":"2025-04-30T19:44:17.914Z","repository":{"id":44620293,"uuid":"232164454","full_name":"LucasMendesl/express-decorator-router","owner":"LucasMendesl","description":":zap: use decorators in a simple way without transpiling javascript code","archived":false,"fork":false,"pushed_at":"2023-01-24T12:12:44.000Z","size":554,"stargazers_count":48,"open_issues_count":3,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-26T06:53:22.974Z","etag":null,"topics":["dependency-injection","express-decorators","expressjs","inversion-of-control","nodejs","routing-decorators","without-transpiling"],"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/LucasMendesl.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":"2020-01-06T18:51:31.000Z","updated_at":"2025-03-21T22:42:07.000Z","dependencies_parsed_at":"2023-02-13T21:16:11.247Z","dependency_job_id":null,"html_url":"https://github.com/LucasMendesl/express-decorator-router","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LucasMendesl%2Fexpress-decorator-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LucasMendesl%2Fexpress-decorator-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LucasMendesl%2Fexpress-decorator-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LucasMendesl%2Fexpress-decorator-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LucasMendesl","download_url":"https://codeload.github.com/LucasMendesl/express-decorator-router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251772707,"owners_count":21641487,"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":["dependency-injection","express-decorators","expressjs","inversion-of-control","nodejs","routing-decorators","without-transpiling"],"created_at":"2025-02-25T10:33:23.574Z","updated_at":"2025-04-30T19:44:17.889Z","avatar_url":"https://github.com/LucasMendesl.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# express-decorator-router\n\n[![NPM](https://nodei.co/npm/express-decorator-router.png?compact=true)](https://www.npmjs.com/package/express-decorator-router)\n\n\u003e use decorators in a simple way without transpiling javascript code\n## Why?\n\nHave you ever considered using the decorators feature using vanilla javascript to automate the creation of express routes?\n\nThe [express-decorator-router](https://github.com/LucasMendesl/express-decorator-router) package came to solve this problem in a simple and didactic way, without the need for transpiling processes in your code.\n\nThis package is intended to avoid unnecessary creation of two files where one file contains the route definition and the other file has the function that handles the route request / response process, leaving simpler maintenance and more scalable code.\n\n### New in **0.2.0**\n\n\u003e Now, you can work with dependency injection.\n\n## Usage\n\nLet's take a short example using the decorators on a prototype-based controller.\n\n```js\nconst {\n  get,\n  controller\n} = require ('express-decorator-router')\n\nconst controllerFactoryDecorator = controller('/users')\n\nclass UsersController {\n  constructor () {/*...class constructor definition*/}\n        \n  getUsers (ctx) {/*...process to get users (database, network, etc)*/}\n       \n  getUsersById (ctx) {/*...implementation of another endpoint*/}\n}\n\nmodule.exports = controllerFactoryDecorator(UsersController, {\n  getUsers: get (),\n  getUsersById: get ('/:id')\n})\n```\n\nthe controller function returns a high order function where the decorator definition is made by associating a decorator with a class method as seen in the example above.\n\nLet's take another example, but let's use middleware and a literal object to define a controller:\n\n```js\nconst {\n  get,\n  post,\n  controller\n} = require ('express-decorator-router')\n\nconst authExampleMiddleware = (req, res, next) =\u003e {\n  if (!req.user) return next(new Error('invalid user'))      \n  return next ()\n}\n\nconst controllerFactoryDecorator = controller('/tasks', authExampleMiddleware)\n\nconst getTasks = ctx =\u003e {/*...*/}\nconst createTask = ctx =\u003e {/*...*/}\n\nmodule.exports = controllerFactoryDecorator({\n  getTasks,\n  createTask\n}, {\n  getTasks: get(),\n  createTask: post()\n})\n```\n\nIn the example above, we create middleware to authenticate users and associate it with the controller function, so middleware logic will be applied to all controller methods. The same technique can be used at the method level.\n\n**Example:**\n\n```js\n// only getTasks method requires authentication for access\nmodule.exports = controller ('/tasks') ({getTasks, createTask}, {\n  getTasks: get (authExampleMiddleware),\n  createTask: post ()\n})\n```\n\nWhen we define a controller, we can pass two arguments to function, the first being the base path of the controller and the second an array containing middleware (the same arguments are accepted by route decorators). If the controller function does not receive any arguments, the path is defined by the value received by the method decorator. Let's look at an example:\n\n```js\n\nconst middlewareTest = (req, res, next) =\u003e { /*any middleware implementation*/ }\nconst anotherMiddlewareTest = (req, res, next) =\u003e { /*any middleware implementation*/ }\n\nmodule.exports = controller () ({\n  getTasks,\n  createTask\n}, {\n  getTasks: get ('/tasks', middlewareTest), // after the path, it is possible to pass an array of middleware\n  createTask: post ('/tasks', anotherMiddlewareTest)\n})\n```\n\nOnce the decorators are applied, every controller instance (being prototype or literal object based) will receive an array of routes, where the metadata of each route is defined, making it possible to dynamically assemble the routes.\n\n## Awilix integration (Dependency Injection)\n\nTo enforce best practices when using this library, you can use [Awilix](https://github.com/jeffijoe/awilix/) to work with an IoC Container, aiming for decoupling our services and improving our architecture.\n\nThe [express-decorator-router](https://github.com/LucasMendesl/express-decorator-router) package has some features to make the process easier of working with dependency injection, building a container with a map associating a service name with a service instance (class or function) working together with `inject` function.\n\nLet's take a short example using dependency injection with awilix.\n\n```js\nconst express = require('express')\nconst taskService = require('./tasks/service')\nconst userService = require('./users/service')\nconst newsService = require('./news/service')\nconst {\n  useAwilixControllers,\n  awilix,\n  scopePerRequest\n} = require('express-decorator-router')\n\nconst app = express()\nconst router = express.Router()\n\n//create awilix container\nconst container = awilix.createContainer()\n\n//registry your services\ncontainer.register({\n\ttaskService: awilix.asValue(taskService).scoped(),\n\tuserService: awilix.asValue(userService).scoped(),\n\tnewsService: awilix.asValue(newsService).scoped()\n})\n\napp.use(express.json())\n\n//injects the container in request scope\napp.use(scopePerRequest(container))\n\n//injects userService into request object with a `inject` middleware function\napp.get('/user/login', inject('userService'), (request, response) =\u003e {\n  const { userService } = request\n  return userService.login(request.body)\n    .then(ok =\u003e response.status(200).json({ message: \"OK\" }))\n    .catch(err =\u003e response.status(500).json({ message: \"Error...\" }))\n})\n```\n\n\u003e [TIP]: If you need more information about `awilix`, i really recommend visiting the repository and checking [package documentation](https://github.com/jeffijoe/awilix/blob/master/README.md).\n\n## Register Controllers\n\nBefore putting the application to run, it is necessary to re-bind the controller methods to the routes using the metadata produced by the decorators. The [express-decorator-router](https://github.com/LucasMendesl/express-decorator-router) package has a feature that will automatically register express routes. Let's look at an example:\n\n```js\n\nconst express             = require('express')\nconst cors                = require('cors')\nconst { useControllers, useAwilixControllers }  = require('express-decorator-router')\n\nconst app             = express()\nconst router          = express.Router()\n\napp.use(cors())\napp.use(express.json())\n\napp.use('/api', useControllers({\n   router,\n   controllerExpression: `${__dirname}/**/controller.js`\n}))\n\n//or if you use middleware without route prefix\napp.use(useControllers({\n   router,\n   controllerExpression: `${__dirname}/**/controller.js`\n}))\n\n//or if you use awilix controllers\napp.use('/api/awilix', useAwilixControllers({\n\trouter,\n\tcontrollerExpression: `${__dirname}/**/controller.js`\n}))\n```\n\nThe **useControllers** and **useAwilixControllers** methods uses two parameters, the first is the routing mechanism and the second is a [glob](https://github.com/isaacs/node-glob) expression that has the responsibility of finding all controllers that match the pattern of the expression, the only difference between **useControllers** and **useAwilixControllers** is that the awilix require to use a container registration for your dependency injection.\n\n### Example\n\nYou can see a demo in the [example](https://github.com/LucasMendesl/express-decorator-router/tree/master/example) folder.\n\n\n### Decorators API\n\n* `register ({ routes: Function, controllerExpression: string  }): Function`\n* `controller (path: string, ...middlewares?:Function []): Function`\n* `route (method: string, methodPath: string, ...middlewares?:Function []): Function`\n* `head`, `options`, `get`, `post`, `put`, `patch`, `del`, `delete`, `all`: partial functions provided by the `route` method that automatically supply the `httpMethod` argument.\n\n\n## Run Tests\n\n```bash\n  npm install\n  npm test\n```\n\n## Contributing\n\nContributions via pull requests are welcome :-).\n\n## License\n\nMIT © [Lucas Mendes Loureiro](http://github.com/lucasmendesl)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucasmendesl%2Fexpress-decorator-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flucasmendesl%2Fexpress-decorator-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucasmendesl%2Fexpress-decorator-router/lists"}