Search code examples
javascriptexpresspointfree

Express and calling response.json in a point free fashion doesn't work in Promise.then


Something greatly surprised me today. I came across a bunch of express route handlers basically look like this (there are more and real function calls, but for the sake of legibility:

app.get('/api/foo', (req, resp) => {
  Promise.resolve({one: 1})
    .then(data=>resp.json(data))
})

So I, as the clever javascript programmer, think I can step away from the anonymous function and just let the then function call resp.json directly:

app.get('/api/foo', (req, resp) => {
  Promise.resolve({one: 1})
    .then(resp.json)
})

But when I try that I never get a response and see this in the node console:

Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'app' of undefined

To my eyes .then(resp.json) and .then(data=>resp.json(data)) should be equivalent. It's a scope thing, to be sure, but I'd love an explanation and perhaps a workaround.


Solution

  • That's because resp is an object with it's own properties, so more than likely the data that is used by the json function is contained within the resp object.

    When you pass the function resp.json by itself to then, you aren't passing the resp object, or any of its information, along with it. In essence, the then call is just "borrowing" the function json from the resp object. Just the function body itself though, no scope or implicit values.

    More than likely, the function body of json uses this somewhere, at which point you will be getting an invalid (probably global) object, instead of resp.

    To remedy, you can do

       Promise.resolve({one: 1})
        .then(resp.json.bind(resp))