Coder Social home page Coder Social logo

express-http-context's Introduction

travis coveralls npm npm david

Express HTTP Context

Get and set request-scoped context anywhere. This is just an unopinionated, idiomatic ExpressJS implementation of cls-hooked (forked from continuation-local-storage). It's a great place to store user state, claims from a JWT, request/correlation IDs, and any other request-scoped data. Context is preserved even over async/await (in node 8+).

How to use it

Install: npm install --save express-http-context
(Note: For node v4-7, use the legacy version: npm install --save express-http-context@<1.0.0)

Use the middleware immediately before the first middleware that needs to have access to the context. You won't have access to the context in any middleware "used" before this one.

Note that some popular middlewares (such as body-parser, express-jwt) may cause context to get lost. To workaround such issues, you are advised to use any third party middleware that does NOT need the context BEFORE you use this middleware.

var express = require('express');
var httpContext = require('express-http-context');

var app = express();
// Use any third party middleware that does not need access to the context here, e.g. 
// app.use(some3rdParty.middleware);
app.use(httpContext.middleware);
// all code from here on has access to the same context for each request

Set values based on the incoming request:

// Example authorization middleware
app.use((req, res, next) => {
	userService.getUser(req.get('Authorization'), (err, result) => {
		if (err) {
			next(err);
		} else {
			httpContext.set('user', result.user)
			next();
		}
	});
});

Get them from code that doesn't have access to the express req object:

var httpContext = require('express-http-context');

// Somewhere deep in the Todo Service
function createTodoItem(title, content, callback) {
	var user = httpContext.get('user');
	db.insert({ title, content, userId: user.id }, callback);
}

You can access cls namespace directly as (it may be useful if you want to apply some patch to it, for example https://github.com/TimBeyer/cls-bluebird):

var ns = require('express-http-context').ns;

Troubleshooting

To avoid weird behavior with express:

  1. Make sure you require express-http-context in the first row of your app. Some popular packages use async which breaks CLS.

For users of Node 10

  1. Node 10.0.x - 10.3.x are not supported. V8 version 6.6 introduced a bug that breaks async_hooks during async/await. Node 10.4.x uses V8 v6.7 in which the bug is fixed. See: nodejs/node#20274.

See Issue #4 for more context. If you find any other weird behaviors, please feel free to open an issue.

Contributors

  • Steve Konves (@skonves)
  • Amiram Korach (@amiram)
  • Yoni Rabinovitch (@yonirab)
  • DontRelaX (@dontrelax)
  • William Durand (@willdurand)

Interesting in contributing? Take a look at the Contributing Guidlines

express-http-context's People

Contributors

amiram avatar dependabot[bot] avatar dmitriyp-comigo avatar dontrelax avatar jacobdfriedmann avatar simenb avatar skonves avatar willdurand avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

express-http-context's Issues

Incompatible with node 10.15.1

I'm using node 10.15.1. It looks like must be worked since 10.15.1 is >=10.4.0. But It does not work:

npm install --save express-http-context

npm ERR! code ENOTSUP
npm ERR! notsup Unsupported engine for [email protected]: wanted: {"node":">=8.0.0 - <10.0.0 || >=10.4.0"} (current: {"node":"10.15.1","npm":"6.4.1"})
npm ERR! notsup Not compatible with your version of node/npm: [email protected]
npm ERR! notsup Not compatible with your version of node/npm: [email protected]
npm ERR! notsup Required: {"node":">=8.0.0 - <10.0.0 || >=10.4.0"}
npm ERR! notsup Actual: {"npm":"6.4.1","node":"10.15.1"}

Ships with ES6 code targeting browsers

The browser.js file uses arrow functions, which are not supported on some older browsers. Since this code is targeting a browser runtime, it might make sense to ship ES5 compatible code instead. In order to not complicate the repos distribution, I'd advocate for just changing the source.

While this could be solved at the individual project level by allow-listing this module for compilation, I think most people who bundle code to target the browser assume the version shipped in node modules has been pre-compiled to a lowest-common-denominator.

Context undefined when used with routing-controllers

I've configured the context on ExpressJs app as a dependency on startup and also set it up as global middleware for every request.
The code works like a charm when using routing-controllers for Get, Put and Post
But, using @Body decorator into a PUT/POST method, it becomes undefined.
Also using body-parser, injecting decorator @JSON, the context get lost.

Working cases:

@get('/data')
public getData():Promise {
httpContext.get('contextId');//Got data
return new Promise;
}

@get('/data')
public getData(@Req() req):Promise {
httpContext.get('contextId');//Got data
var a = req.a;
return new Promise((resolve) => getData(a){
resolve(response);
});
}

@post('/data')
public setData():Promise {
httpContext.get('contextId'); //Got data
var a = 'some random data';
return new Promise((resolve) => setData(a){
resolve(response);
});
}

@post('/data')
public setData(@Req() req):Promise {
httpContext.get('contextId'); //Got undefined
var a = req.a;
return new Promise((resolve) => setData(a){
resolve(response);
});
}

Not working cases:

@UseBefore(json())
@post('/data')
public setData(@Req() req):Promise {
httpContext.get('contextId'); //Got undefined
var a = req.a;
return new Promise((resolve) => setData(a){
resolve(response);
});
}

@post('/data')
public setData(@Body() data):Promise {
httpContext.get('contextId'); //Got undefined
return new Promise((resolve) => setData(data){
resolve(response);
});
}

@put('/data')
public setData(@Body() data):Promise {
httpContext.get('contextId'); //Got undefined
return new Promise((resolve) => setData(data){
resolve(response);
});
}

ns active null

Hi guys, how are you?

I'm working with your library in micro services. We have a few libraries and we save some data in context but since version 1.1.0 is not saving or getting anything. In Debugging i see that when is trying to validate if namespace exists and is active, active is null. I'm calling middleware when the express server start.

Thoughts?

Thanks!
Regards!

body-parser and async are breaking CLS

To avoid weird behavior with express:

  1. Make sure you require express-http-context in the first row of your app. Some popular pkgs use async which breaks CLS.
  2. If you use body-parser, register it in express before you register express-http-context's middleware. I did after seeing that all post requests lost the context.

Cannot find module.

npm install --save express-http-router
var httpContext = require('express-http-context');
npm start
cannot find module

when I run node console, I can require the module fine.
The folder in in my node_modules for the project.

Any ideas?

Got undefined when using ecmascript

when using ES6 I get undefined

// app.mjs
import httpContext from "express-http-context"
import express from 'express'

const app = express();

app.listen(5000,()=> console.log('listening'))

// Use any third party middleware that does not need access to the context here, e.g.
app.use(httpContext.middleware);
// all code from here on has access to the same context for each request




app.get('/', (req, res, next) => {
    let code = httpContext.get('status')
httpContext.set('status', 20)

    console.log('code')
    console.log(code)
    res.send('route')
})

What's the difference with zonejs?

I was looking for a solution like this one and I saw several good candidates, but I did not search enough, yet, to understand the true differences between each. Until then maybe you can enlight me about the differences between express-http-context and zonejs (in a MW). Maybe it is more a question for the cls-hook author but as I saw your project I jump on the occasion :)

Error on get/set before using middleware

If the middleware is not run, the context's namespace is not created. If get() or set() is called, an error will occur.

Steps to repro:

var context = require("express-http-context")
context.get('key');

FWIW, the current test does not catch this because previously run tests end up created the namespace.

how is Concurrenct requests are handled for this package, if i set request object with the same request name??

if i share the user permission object with the same name like so

httpContext.set('permission', permission);

and if concurrent requests reach the express server, wont't this same the permission object to the unintended user due to

  1. same permission name, or due to
  2. some blocking code holding one request and the other concurrent request changing the permission object, and by the time the first request finishes it's task it get the updated permission object, which it doesn't belong to it

Return wrong context in promise chain

I'm using express-http-context to store request-id(generate each time new request arrived automatically) and get request-id anytime, anywhere I want.
In normal case its working fine but if I get context in promise chain it always return context of the first request. Please help me how to always get context of current request.

Thanks a lot!

Context is lost sometimes during one request

I've noticed very strange behavior of library.
I make several requests to external API during 1 request to my own and I want to write logs of each external request into DB. Before each request I'm trying to get the ID of current document which was set in context. But sometimes this value is undefined and sometimes not.

const request = require('request');
const mongoose = require('mongoose');
const httpContext = require('express-http-context');
const PolicyLog = mongoose.model('PolicyLog');

const updatePolicyLog = (id, log) => {
  return new Promise((resolve, reject) => {
    PolicyLog.update({ "policyId": mongoose.Types.ObjectId(id) },
      { $push: { logs: log } }
    ).then(() => {
      resolve();
    }).catch(err => {
      reject(err);
    });
  });
};

exports.createPolicy = (policy) => {
  return new Promise((resolve, reject) => {
    // prepare request body and do some other stuff here

    let options = {}; // request options (url, method, headers & body)
    request(options, (error, response, body) => {
      if (error)
        reject(error);

      let policyLocalId = httpContext.get("policyLocalId");
      console.log(policyLocalId)  // sometimes it's undefined
      updatePolicyLog(policyLocalId, {
        method: "reqName",
        request: "reqBody",
        response: body
      }).then(() => {
        resolve();
      }).catch(err => {
        return reject(err)
      });
    });

  });
};

node: 6.16.0
npm: 3.10.10
express-http-context: ^1.0.4
express: ^4.14.0

Question: how to get something like this, but for non-requests (eg jobs)

This looks amazing, and I plan on using it to allow better correlation of logs in my system. I know it only works with express, and specifically http requests. However, I also have many scheduled jobs that I'd like to be able to trace with a shared context, shared logger, or shared correlation id. CLS is new to me, so my question is, is this at all possible outside the context of http requests and express? Any pointers in the right direction would be greatly appreciated!

Support browser compilation (with noop functions)

Hi, thanks for your lib!

We'd like to use your lib in our project but we do server-side rendering and the codebase is shared between node and the browser. This lib obviously does not work in the browser (and it is not designed for that), but could we add some improvements to be able to compile it for the browser?

I have created a lib that does that: https://github.com/willdurand/universal-express-http-context, it requires your lib by default and provides a noop interface for the browser: https://github.com/willdurand/universal-express-http-context/blob/master/browser.js.

That allows us to use the lib in both contexts, even though only the server context really relies on the HTTP context and CLS.

How would you feel about merging those changes into your lib so that more people can benefit from that and I don't have to watch this project all the time to make sure we are up-to-date?

Thanks!

feature request: get all keys or values

I want to be able to get all keys and values stored in the current http context without needing to know all the keys.

To do this, I'd like a method exposed that will return an array of all keys. Or perhaps a method that returns an array of arrays of key and value pairs.

Similar to Object.keys or Object.entries on a javascript object.

Context lost after making the first call to odbc

const app = require('express')();
const httpContext = require('express-http-context');
var db = require('odbc')();
const cn = "DRIVER={ODBC Driver 13 for SQL Server};SERVER=SOMESERVER,SOMEPORT;DATABASE=somedb;Trusted_Connection=Yes"

app.use(httpContext.middleware);

app.get('/', (req, res) => {
    httpContext.set('foo', 'bar');

    console.log(httpContext.get('foo'));      // prints 'bar'

    db.open(cn, (err) => {
        if (err) throw err;

        console.log(httpContext.get('foo'));  // prints undefined!
        ...
    });
});
...

My environment is

RedHat Enterprise Linux 7.2 (maipo)
Node: 6.9.1
npm: 5.6.0
express-http-context: 1.0.4 (have tried 1.0.0 as well)

This is not working with post express request

I setup a traced id in express.js
httpContext.set('traceId', uuid.v4())
But when I try to fetch it using httpContext.get('traceId') it doesnt seem to work and gives me undefined for POST express request.
It works fine for GET request.
Not sure what is wrong with this

Use Async Hooks

Add support to the Async Hooks API in Node 8 rather than CLS

Performance Benchmark

Thanks for building and maintaining this one-of-its-kind library. Are there any noted / possible performance hits using it?

Are there any benchmarks that describe / test the performance when using it?

Thanks,

cls-hooked error

Hi there, I'm getting an error with express-http-context v1.2.0
I'm not sure why but I'm getting the following error

node_modules/express-http-context/index.d.ts:2:27 - error TS7016: Could not find a declaration file for module 'cls-hooked'. '/home/josh/Projects/express-api/node_modules/cls-hooked/index.js' implicitly has an 'any' type.
  Try `npm install @types/cls-hooked` if it exists or add a new declaration (.d.ts) file containing `declare module 'cls-hooked';`

2 import { Namespace } from 'cls-hooked';

Could you point me in the right direction please?

Context not available in unhandledRejection handler

I added an express middleware that creates a uuid for every incoming request so that I can easily correlate logs belonging to a single service call.

When adding this code to one of the service classes in order to generate an unhandled promise rejection:

new Promise((res, rej) => {
   rej(new Error('some rejection'));
});

it seems as if the process.on('unhandledRejection', ...) handler does not have access to the context.

Is this expected behaviour or a bug in the library?

Context lost after mysql query

I'm trying to get http context after a mysql query in express app. The context seems to be lost after executing a query:

const app = require('express')();
const httpContext = require('express-http-context');
const connection = require('mysql').createConnection({ ... });

connection.connect();

app.use(httpContext.middleware);

app.get('/', (req, res) => {
    httpContext.set('foo', 'bar');

    console.log(httpContext.get('foo'));      // prints 'bar'

    connection.query('SELECT * FROM some.table', (err, result, fields) => {
        if (err) throw err;

        console.log(httpContext.get('foo'));  // prints undefined!
        ...
    });
});
...

Please help

context doesn't work when called through microservices

suppose i have 2 micro-service , service a and service b
when i call some api of service b through service a , httpContext.get('key') returns undefined
I have same implementation of express-http-context in both the service a and b

P.S when i am calling individual api through postman , context works wonderfully.

please help

Is it possible to stub or mock httpcontext in unit test ?

I have used express-http-context in node(express) which is working fine.
But I want to write unit test for some methods where i have used httpContext , so while calling that method directly from unit test code the httpcontext is undefined.

Is there is any possible solution for that ?

Thanks

using express-http-context with sails js

I use express-http-context with middleware writing log when a request coming, and store the unique id for in http context using httpContext.set('reqId', req.requestInfo.id);, and with every log using console.log or console.error, i override them to print the unique id using httpContext.get('reqId').
The problem is that I can't get the id, it is jus the blank.
Is there someone get this problem? If so, please help me to solve it. Thank you

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.