{"id":16837667,"url":"https://github.com/jeffijoe/awilix-express","last_synced_at":"2026-02-08T12:11:33.174Z","repository":{"id":42666868,"uuid":"84553402","full_name":"jeffijoe/awilix-express","owner":"jeffijoe","description":"Awilix helpers/middleware for Express","archived":false,"fork":false,"pushed_at":"2024-01-11T15:47:33.000Z","size":932,"stargazers_count":112,"open_issues_count":5,"forks_count":7,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-04-18T13:47:59.324Z","etag":null,"topics":["awilix","dependency-injection","di","express","inversion-of-control"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/jeffijoe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-03-10T11:30:58.000Z","updated_at":"2024-03-21T14:24:04.000Z","dependencies_parsed_at":"2024-01-17T15:04:40.246Z","dependency_job_id":null,"html_url":"https://github.com/jeffijoe/awilix-express","commit_stats":null,"previous_names":["talyssonoc/awilix-express"],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffijoe%2Fawilix-express","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffijoe%2Fawilix-express/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffijoe%2Fawilix-express/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffijoe%2Fawilix-express/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeffijoe","download_url":"https://codeload.github.com/jeffijoe/awilix-express/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247436289,"owners_count":20938533,"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":["awilix","dependency-injection","di","express","inversion-of-control"],"created_at":"2024-10-13T12:18:27.368Z","updated_at":"2026-02-08T12:11:33.169Z","avatar_url":"https://github.com/jeffijoe.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# awilix-express\n\n[![npm version](https://badge.fury.io/js/awilix-express.svg)](https://badge.fury.io/js/awilix-express)\n[![CI](https://github.com/jeffijoe/awilix-express/actions/workflows/ci.yml/badge.svg)](https://github.com/jeffijoe/awilix-express/actions/workflows/ci.yml)\n[![Coverage Status](https://coveralls.io/repos/github/jeffijoe/awilix-express/badge.svg?branch=master)](https://coveralls.io/github/jeffijoe/awilix-express?branch=master)\n![Typings Included](https://img.shields.io/badge/typings-included-brightgreen.svg)\n\nAwilix helpers, router and scope-instantiating middleware for **Express**. 🐨\n\n\u003e ✨ **NEW IN V1**: [first-class router support with auto-loading!](#awesome-usage) 🚀\n\n# Table of Contents\n\n- [awilix-express](#awilix-express)\n- [Table of Contents](#table-of-contents)\n- [Installation](#installation)\n- [Basic Usage](#basic-usage)\n- [Awesome Usage](#awesome-usage)\n- [Why do I need it?](#why-do-i-need-it)\n  - [Manual](#manual)\n  - [Using `awilix-express`](#using-awilix-express)\n- [API](#api)\n- [Contributing](#contributing)\n  - [`npm run` scripts](#npm-run-scripts)\n- [Author](#author)\n\n# Installation\n\n```\nnpm install --save awilix-express\n```\n\n# Basic Usage\n\nAdd the middleware to your Express app.\n\n```js\nconst { asClass, asValue, createContainer } = require('awilix')\nconst { scopePerRequest } = require('awilix-express')\n\nconst container = createContainer()\ncontainer.register({\n  // Scoped lifetime = new instance per request\n  // Imagine the TodosService needs a `user`.\n  // class TodosService { constructor({ user }) { } }\n  todosService: asClass(TodosService).scoped(),\n})\n\n// Add the middleware, passing it your Awilix container.\n// This will attach a scoped container on the context.\napp.use(scopePerRequest(container))\n\n// Now you can add request-specific data to the scope.\napp.use((req, res, next) =\u003e {\n  req.container.register({\n    user: asValue(req.user), // from some authentication middleware...\n  })\n\n  return next()\n})\n```\n\nThen in your route handlers...\n\n```js\nconst { makeInvoker } = require('awilix-express')\n\nfunction makeAPI({ todosService }) {\n  return {\n    find: (req, res) =\u003e {\n      return todosService.find().then((result) =\u003e {\n        res.send(result)\n      })\n    },\n  }\n}\n\nconst api = makeInvoker(makeAPI)\n\n// Creates middleware that will invoke `makeAPI`\n// for each request, giving you a scoped instance.\nrouter.get('/todos', api('find'))\n```\n\n# Awesome Usage\n\n**As of `awilix-express@1.0.0`**, we ship with `Express.Router` bindings for [`awilix-router-core`][awilix-router-core]!\nThis is cool because now your routing setup can be streamlined with first-class Awilix support!\n\nThe Awilix-based router comes in 2 flavors: **a builder** and **ESNext decorators**.\n\n**`routes/todos-api.js`** - demos the builder pattern\n\n```js\nimport bodyParser from 'body-parser'\nimport { authenticate } from './your-auth-middleware'\nimport { createController } from 'awilix-express' // or `awilix-router-core`\n\nconst API = ({ todoService }) =\u003e ({\n  getTodo: async (req, res) =\u003e {\n    res.send(await todoService.get(req.params.id))\n  },\n  createTodo: async (req, res) =\u003e {\n    res.send(await todoService.create(req.body))\n  },\n})\n\nexport default createController(API)\n  .prefix('/todos') // Prefix all endpoints with `/todo`\n  .before([authenticate()]) // run authentication for all endpoints\n  .get('/:id', 'getTodo') // Maps `GET /todos/:id` to the `getTodo` function on the returned object from `API`\n  .post('', 'createTodo', {\n    // Maps `POST /todos` to the `createTodo` function on the returned object from `API`\n    before: [bodyParser()], // Runs the bodyParser just for this endpoint\n  })\n```\n\n**`routes/users-api.js`** - demos the decorator pattern\n\n```js\nimport bodyParser from 'body-parser'\nimport { authenticate } from './your-auth-middleware'\nimport { route, GET, POST, before } from 'awilix-express' // or `awilix-router-core`\n\n@route('/users')\nexport default class UserAPI {\n  constructor({ userService }) {\n    this.userService = userService\n  }\n\n  @route('/:id')\n  @GET()\n  @before([authenticate()])\n  async getUser(req, res) {\n    res.send(await this.userService.get(req.params.id))\n  }\n\n  @POST()\n  @before([bodyParser()])\n  async createUser(req, res) {\n    res.send(await this.userService.create(req.body))\n  }\n}\n```\n\n**`server.js`** - CommonJS / synchronous\n\n```js\nimport Express from 'express'\nimport { asClass, createContainer } from 'awilix'\nimport { loadControllers, scopePerRequest } from 'awilix-express'\n\nconst app = Express()\nconst container = createContainer().register({\n  userService: asClass(/*...*/),\n  todoService: asClass(/*...*/),\n})\napp.use(scopePerRequest(container))\n// Loads all controllers in the `routes` folder\n// relative to the current working directory.\n// This is a glob pattern.\napp.use(loadControllers('routes/*.js', { cwd: __dirname }))\n\napp.listen(3000)\n```\n\n**`server.js`** - ESM / async\n\nWhen using ES modules, pass `esModules: true`. This makes `loadControllers` return a `Promise\u003cRouter\u003e`, so you'll need to `await` it.\n\n```js\nimport Express from 'express'\nimport { asClass, createContainer } from 'awilix'\nimport { loadControllers, scopePerRequest } from 'awilix-express'\n\nconst app = Express()\nconst container = createContainer().register({\n  userService: asClass(/*...*/),\n  todoService: asClass(/*...*/),\n})\napp.use(scopePerRequest(container))\napp.use(await loadControllers('routes/*.js', { esModules: true }))\n\napp.listen(3000)\n```\n\nPlease see the [`awilix-router-core`][awilix-router-core] docs for information about the full API.\n\n# Why do I need it?\n\nYou can certainly use Awilix with Express without this library, but follow along and you might see why it's useful.\n\nImagine this simple imaginary Todos app, written in ES6:\n\n```js\n// A totally framework-independent piece of application code.\n// Nothing here is remotely associated with HTTP, Express or anything.\nclass TodosService {\n  constructor({ currentUser, db }) {\n    // We depend on the current user!\n    this.currentUser = currentUser\n    this.db = db\n  }\n\n  getTodos() {\n    // use your imagination ;)\n    return this.db('todos').where('user', this.currentUser.id)\n  }\n}\n\n// Here's a Express API that calls the service\nclass TodoAPI {\n  constructor({ todosService }) {\n    this.todosService = todosService\n  }\n  getTodos(req, res) {\n    return this.todosService.getTodos().then((todos) =\u003e res.send(todos))\n  }\n}\n```\n\nSo the problem with the above is that the `TodosService` needs a `currentUser` for it to function. Let's first try solving this manually, and then with `awilix-express`.\n\n## Manual\n\nThis is how you would have to do it without Awilix at all.\n\n```js\nimport db from './db'\n\nrouter.get('/todos', (req, res) =\u003e {\n  // We need a new instance for each request,\n  // else the currentUser trick wont work.\n  const api = new TodoAPI({\n    todosService: new TodosService({\n      db,\n      // current user is request specific.\n      currentUser: req.user,\n    }),\n  })\n\n  // invoke the method.\n  return api.getTodos(req, res)\n})\n```\n\nLet's do this with Awilix instead. We'll need a bit of setup code.\n\n```js\nimport { asValue, createContainer, Lifetime } from 'awilix'\n\nconst container = createContainer()\n\n// The `TodosService` lives in services/TodosService\ncontainer.loadModules(['services/*.js'], {\n  // we want `TodosService` to be registered as `todosService`.\n  formatName: 'camelCase',\n  resolverOptions: {\n    // We want instances to be scoped to the Express request.\n    // We need to set that up.\n    lifetime: Lifetime.SCOPED,\n  },\n})\n\n// imagination is a wonderful thing.\napp.use(someAuthenticationMethod())\n\n// We need a middleware to create a scope per request.\n// Hint: that's the scopePerRequest middleware in `awilix-express` ;)\napp.use((req, res, next) =\u003e {\n  // We want a new scope for each request!\n  req.container = container.createScope()\n  // The `TodosService` needs `currentUser`\n  req.container.register({\n    currentUser: asValue(req.user), // from auth middleware... IMAGINATION!! :D\n  })\n  return next()\n})\n```\n\nOkay! Let's try setting up that API again!\n\n```js\nexport default function (router) {\n  router.get('/todos', (req, res) =\u003e {\n    // We have our scope available!\n    const api = new TodoAPI(req.container.cradle) // Awilix magic!\n    return api.getTodos(req, res)\n  })\n}\n```\n\nA lot cleaner, but we can make this even shorter!\n\n```js\nexport default function (router) {\n  // Just invoke `api` with the method name and\n  // you've got yourself a middleware that instantiates\n  // the API and calls the method.\n  const api = (methodName) =\u003e {\n    // create our handler\n    return function (req, res) {\n      const controller = new TodoAPI(req.container.cradle)\n      return controller[method](req, res)\n    }\n  }\n\n  // adding more routes is way easier!\n  router.get('/todos', api('getTodos'))\n}\n```\n\n## Using `awilix-express`\n\nIn our route handler, do the following:\n\n```js\nimport { makeInvoker } from 'awilix-express'\n\nexport default function (router) {\n  const api = makeInvoker(TodoAPI)\n  router.get('/todos', api('getTodos'))\n}\n```\n\nAnd in your express application setup:\n\n```js\nimport { asValue, createContainer, Lifetime } from 'awilix'\nimport { scopePerRequest } from 'awilix-express'\n\nconst container = createContainer()\n\n// The `TodosService` lives in services/TodosService\ncontainer.loadModules(\n  [\n    ['services/*.js', Lifetime.SCOPED], // shortcut to make all services scoped\n  ],\n  {\n    // we want `TodosService` to be registered as `todosService`.\n    formatName: 'camelCase',\n  },\n)\n\n// imagination is a wonderful thing.\napp.use(someAuthenticationMethod())\n\n// Woah!\napp.use(scopePerRequest(container))\napp.use((req, res, next) =\u003e {\n  // We still want to register the user!\n  // req.container is a scope!\n  req.container.register({\n    currentUser: asValue(req.user), // from auth middleware... IMAGINATION!! :D\n  })\n})\n```\n\nNow **that** is way simpler!\n\n```js\nimport { makeInvoker } from 'awilix-express'\n\nfunction makeTodoAPI({ todosService }) {\n  return {\n    getTodos: (req, res) =\u003e {\n      return todosService.getTodos().then((todos) =\u003e res.send(todos))\n    },\n  }\n}\n\nexport default function (router) {\n  const api = makeInvoker(makeTodoAPI)\n  router.get('/api/todos', api('getTodos'))\n}\n```\n\nThat concludes the tutorial! Hope you find it useful, I know I have.\n\n# API\n\nThe package exports everything from `awilix-router-core` as well as the following **Express middleware factories**:\n\n- `scopePerRequest(container)`: creates a scope per request.\n- `controller(decoratedClassOrController)`: registers routes and delegates to Express.Router.\n- `loadControllers(pattern, opts)`: loads files matching a glob pattern and registers their exports as controllers. Supports `opts.esModules: true` for ESM projects — when enabled, returns a `Promise\u003cRouter\u003e` instead of `Router`.\n- `makeInvoker(functionOrClass, opts)(methodName)`: using `isClass`, calls either `makeFunctionInvoker` or `makeClassInvoker`.\n- `makeClassInvoker(Class, opts)(methodName)`: resolves \u0026 calls `methodName` on the resolved instance, passing it `req`, `res` and `next`.\n- `makeFunctionInvoker(function, opts)(methodName)`: resolves \u0026 calls `methodName` on the resolved instance, passing it `req`, `res` and `next`.\n- `makeResolverInvoker(resolver, opts)`: used by the other invokers, exported for convenience.\n- `inject(middlewareFactory)`: resolves the middleware per request.\n\n```js\napp.use(\n  inject(({ userService }) =\u003e (req, res, next) =\u003e {\n    /**/\n  }),\n)\n```\n\n# Contributing\n\n## `npm run` scripts\n\n- `npm run test`: Runs tests once\n- `npm run lint`: Lints + formats the code once\n- `npm run cover`: Runs code coverage using `istanbul`\n\n# Author\n\n- Talysson Oliveira Cassiano - [@talyssonoc](https://twitter.com/talyssonoc)\n- Jeff Hansen - [@jeffijoe](https://twitter.com/jeffijoe)\n\n[awilix-router-core]: https://github.com/jeffijoe/awilix-router-core\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffijoe%2Fawilix-express","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeffijoe%2Fawilix-express","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffijoe%2Fawilix-express/lists"}