{"id":19874507,"url":"https://github.com/strongloop/loopback-context","last_synced_at":"2025-05-02T10:31:22.713Z","repository":{"id":37546502,"uuid":"64396357","full_name":"strongloop/loopback-context","owner":"strongloop","description":"Current context for LoopBack applications, based on node-continuation-local-storage","archived":false,"fork":false,"pushed_at":"2021-03-17T13:46:54.000Z","size":67,"stargazers_count":25,"open_issues_count":0,"forks_count":21,"subscribers_count":23,"default_branch":"master","last_synced_at":"2024-04-25T12:03:40.853Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strongloop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null}},"created_at":"2016-07-28T13:07:26.000Z","updated_at":"2023-11-30T00:43:45.000Z","dependencies_parsed_at":"2022-08-18T03:01:31.684Z","dependency_job_id":null,"html_url":"https://github.com/strongloop/loopback-context","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Floopback-context","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Floopback-context/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Floopback-context/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Floopback-context/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strongloop","download_url":"https://codeload.github.com/strongloop/loopback-context/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224152512,"owners_count":17264718,"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":[],"created_at":"2024-11-12T16:23:43.432Z","updated_at":"2024-11-12T16:23:44.155Z","avatar_url":"https://github.com/strongloop.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# loopback-context\n\n**⚠️ LoopBack 3 has reached end of life. We are no longer accepting pull requests or providing \nsupport for community users. The only exception is fixes for critical bugs and security \nvulnerabilities provided as part of support for IBM API Connect customers. (See\n[Module Long Term Support Policy](#module-long-term-support-policy) below.)**\n\nWe urge all LoopBack 3 users to migrate their applications to LoopBack 4 as\nsoon as possible. Refer to our\n[Migration Guide](https://loopback.io/doc/en/lb4/migration-overview.html)\nfor more information on how to upgrade.\n\n## Overview\n\nCurrent context for LoopBack applications, based on cls-hooked.\n\n## WARNING\n\n**`cls-hooked` module uses undocumented `AsyncWrap` API that was introduced to Node.js relatively recently. While this new API seems to be more reliable than the old `async-listener` used by `continuation-local-storage`, there are still cases where the context (local storage) is not preserved correctly. Please consider this risk before using loopback-context.**\n\n### Known issues\n\n- [when](https://www.npmjs.com/package/when), a popular Promise\n   implementation, breaks context propagation. Please consider using the\n   built-in `Promise` implementation provided by Node.js or\n   [Bluebird](https://www.npmjs.com/package/bluebird) instead.\n- Express middleware chains which contain a \"bad\" middleware (i.e. one which\n  breaks context propagation inside its function body, in a way mentioned in\n  this doc) especially if called before other \"good\" ones needs refactoring,\n  in order to prevent the context from getting mixed up among HTTP requests.\n  See usage below for details.\n\n   Discussion: https://github.com/strongloop/loopback-context/issues/17\n\nIn general, any module that implements a custom task queue or a connection pool\nis prone to break context storage. This is an inherent problem of continuation\nlocal storage that needs to be fixed at lower level - first in Node.js core\nand then in modules implementing task queues and connection pools.\n\n## Installation\n\n```\n$ npm install --save loopback-context cls-hooked\n```\n\nMake sure you are running on a Node.js version supported by this module\n(`^4.5`, `^5.10`, `^6.0`, `^7.0`, `^8.2.1` or `^10.14`). When installing, check the output of `npm install`\nand make sure there are no `engine` related warnings.\n\n## Usage\n\n### Setup cls-hooked\n\nTo minimize the likelihood of loosing context in your application, you should\nensure that `cls-hooked` is loaded as the first module of your application, so\nthat it can wrap certain Node.js APIs before any other modules start using these\nAPIs.\n\nOur recommended approach is to add `-r cls-hooked` to node's list of\narguments when starting your LoopBack application.\n\n```\n$ node -r cls-hooked .\n```\n\nIf you are using a process manager like `strong-pm` or `pm2`, then consult\ntheir documentation whether it's possible to configure the arguments used to\nspawn worker processes. Note that `slc run` does not support this feature yet,\nsee [strong-supervisor#56](https://github.com/strongloop/strong-supervisor/issues/56).\n\nAlternatively, you can add the following line as the first line of your main\napplication file:\n\n```js\nrequire('cls-hooked');\n```\n\nThis approach should be compatible with all process managers, including\n`strong-pm`. However, we feel that relying on the order of `require` statements\nis error-prone.\n\n### Configure context propagation\n\nTo setup your LoopBack application to create a new context for each incoming\nHTTP request, configure `per-context` middleware in your\n`server/middleware.json` as follows:\n\n\n```json\n{\n  \"initial\": {\n    \"loopback-context#per-request\": {\n    }\n  }\n}\n```\n\n**IMPORTANT: By default, the HTTP req/res objects are not set onto the current context. You\nneed to set `enableHttpContext` to true to enable automatic population\nof req/res objects.**\n\n```json\n{\n  \"initial\": {\n    \"loopback-context#per-request\": {\n      \"params\": {\n        \"enableHttpContext\": true\n      }\n    }\n  }\n}\n```\n\n### Use the current context\n\nOnce you’ve enabled context propagation, you can access the current context\nobject using `LoopBackContext.getCurrentContext()`. The context will be\navailable in middleware (if it is loaded after the context middleware),\nremoting hooks, model hooks, and custom methods.\n\n```js\nvar LoopBackContext = require('loopback-context');\n\n// ...\n\nMyModel.myMethod = function(cb) {\n  var ctx = LoopBackContext.getCurrentContext();\n  ctx.get('key');\n  ctx.set('key', { foo: 'bar' });\n});\n```\n\n### Bind for concurrency\n\nIn order to workaround the aforementioned concurrency issue with `when` (and\nsimilar `Promise`-like and other libraries implementing custom queues and/or\nconnection pools), it's recommended to activate context binding inside each\nHTTP request or concurrent `runInContext()` call, by using the `bind` option, as\nin this example:\n\n    var ctx = LoopBackContext.getCurrentContext({ bind: true });\n\nWith the option enabled, this both creates the context, and binds the access\nmethods of the context (i.e. `get` and `set`), at once.\n\n**Warning**: this only works if it's **the first expression evaluated** in every\nmiddleware/operation hook/`runInContext()` call etc. that uses\n`getCurrentContext`. (It must be the first expression; it may not be enough if\nit's at the first line). Explanation: you must bind the context while it's still\ncorrect, i.e. before it gets mixed up between concurrent operations affected by\nbugs. Therefore, to be sure, you must bind it before *any* operation.\n\nAlso, with respect to the \"bad\", context-breaking middleware use case mentioned in \"Known issues\"\nbefore, the following 2 lines need to be present at the beginning of the middleware\nbody. At least the \"bad\" one; but, as a preventive measure, they can be present\nin every other middleware of every chain as well, being backward-compatible:\n\n     var badMiddleware = function(req, res, next) {\n       // these 2 lines below are needed\n       var ctx = LoopBackContext.getCurrentContext({bind: true});\n       next = ctx.bind(next);\n       ...\n\nThe `bind` option defaults to `false`. This is only in order to prevent breaking\nlegacy apps; but if your app doesn't have such issue, then you can safely use\n`bind: true` everywhere in your app (e.g. with a\n[codemod](https://github.com/facebook/jscodeshift), or by monkey-patching\n`getCurrentContext()` globally, if you prefer an automated fashion).\n\n**Warning**: this only applies to application modules. In fact, if the module\naffected by the concurrency issue is of this kind, you can easily refactor/write\nyour own code so to enable `bind`. Not if it's a 3rd-party module, nor a\nLoopback non-core module, unless you fork and fix it.\n\n### Use current authenticated user in remote methods\n\nIn advanced use cases, for example when you want to add custom middleware, you\nhave to add the context middleware at the right position in the middleware\nchain (before the middleware that depends on\n`LoopBackContext.getCurrentContext`).\n\n**IMPORTANT: `LoopBackContext.perRequest()` detects the situation when it is\ninvoked multiple times on the same request and returns immediately in\nsubsequent runs.**\n\nHere is a snippet using a middleware function to place the currently\nauthenticated user into the context so that remote methods may use it:\n\n**server/middleware/store-current-user.js**\n```js\nmodule.exports = function(options) {\n  return function storeCurrentUser(req, res, next) {\n    if (!req.accessToken) {\n      return next();\n    }\n\n    app.models.UserModel.findById(req.accessToken.userId, function(err, user) {\n      if (err) {\n        return next(err);\n      }\n      if (!user) {\n        return next(new Error('No user with this access token was found.'));\n      }\n      var loopbackContext = LoopBackContext.getCurrentContext();\n      if (loopbackContext) {\n        loopbackContext.set('currentUser', user);\n      }\n      next();\n    });\n  };\n};\n```\n\n**server/middleware.json**\n```json\n{\n  \"initial\": {\n    \"loopback-context#per-request\": {}\n  },\n  \"auth\": {\n    \"loopback#token\": {}\n  },\n  \"auth:after\": {\n    \"./middleware/store-current-user\": {}\n  }\n}\n```\n\n**common/models/YourModel.json**\n```js\nvar LoopBackContext = require('loopback-context');\nmodule.exports = function(YourModel) {\n  ...\n  //remote method\n  YourModel.someRemoteMethod = function(arg1, arg2, cb) {\n    var ctx = LoopBackContext.getCurrentContext();\n    var currentUser = ctx \u0026\u0026 ctx.get('currentUser');\n    console.log('currentUser.username: ', currentUser.username); // voila!\n    ...\n    cb(null);\n  };\n  ...\n};\n```\n\n## Module Long Term Support Policy\n\nThis module adopts the [Module Long Term Support (LTS)](http://github.com/CloudNativeJS/ModuleLTS) policy, with the following End Of Life (EOL) dates:\n\n| Version | Status          | Published | EOL      |\n| ------- | --------------- | --------- | -------- |\n| 3.x     | End-of-Life     | Jan 2017  | Dec 2020 |\n| 1.x     | End-of-Life     | Aug 2016  | Apr 2019 |\n\nLearn more about our LTS plan in the [docs](https://loopback.io/doc/en/contrib/Long-term-support.html).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrongloop%2Floopback-context","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrongloop%2Floopback-context","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrongloop%2Floopback-context/lists"}