3

I have an existing express endpoint that looks like this:

app.get(`${route}/:id`, async (req, res) => {
    try {
        const id = req.params.id;
        const result = await dbFn(id);
        res.send(result);
    } catch (err) {
        res.status(500).end();
    }
});

And this is going to return an object that looks like:

{
    "id": 123,
    "name": "Foo"
}

Now, I want to extend this API, so that if it has a Accept: application/vnd.v2 header, then it will also fetch some data from a different service, and add that on. (See my related question where using content negotiation is suggested).

ie. the response will be:

{
    "id": 123,
    "name": "Foo", 
    "extraData": {
        "foo": "bar"
    }
}

Now, I can do this with express, here's how I have done it:

  app.get(`${route}/:id`, async (req, res, next) => {
    try {

      const id = req.params.id;
      const jobSeeker = await dbFn(id);
      if (req.accepts("application/vnd.v2")) {
        const response = await axios.get(`${integrationApiPath}/connection/${id}`); 
        const ssiData = response.data; 

        res.send({
          ...jobSeeker, 
          ssiData
        })

      }
      else {
        res.send(jobSeeker);
      }
    } catch (err) {
      res.status(500).end();
    }

  });

But it struck me as a bit of a messy way to do API versioning.

What would be much nicer, is if I can have nginx handling this versioning instead.

That way, I don't need to modify my existing API, I can just create the new service, and have nginx examine the headers, and make both microservice calls and join them together.

Is this possible?

dwjohnston
  • 11,163
  • 32
  • 99
  • 194

1 Answers1

1

But it struck me as a bit of a messy way to do API versioning.

I don't think that this is a bad way to do API versioning, since it's a common way to do it. In addition you can serve the new service in a new subdirectory (e.g. yourwebsite.com/yourservice.../v2/yourFunction).

What would be much nicer, is if I can have nginx handling this versioning instead.

I also don't agree that it would be nicer to let NginX do the "logic" of your webservice, since it's the responsibility of NginX to serve your website/webservice, not to implement the logic.

However, if you still want to merge the requests using NginX you may want to have a look at this question/answer. This answer uses openresty. You may have to install this first.

As described, you can call multiple (in your case 2) services using this code:

location /yourServiceV2 {
    content_by_lua_block {
        local respA = ngx.location.capture("/yourService")
        local respB = ngx.location.capture("/theServiceWhichExtendsYourService")

        ngx.say(respA.body .. respB.body)
    }
}

If you only want to perform the mentioned code under when a specific header is present you can use a if statement like described in this answer. So, your if statement would look like this:

if ($http_accept == 'application/vnd.v2') {
    return 405;
}
Gerard van Helden
  • 1,601
  • 10
  • 13
Marvin Klar
  • 1,869
  • 3
  • 14
  • 32
  • This would be executing `A` then `B` yes? This seems strictly worse than doing it at a layer you can run these requests in parallel I think. – Alex Moore-Niemi Nov 20 '20 at 20:42
  • An example of doing the above in parallel is: https://stackoverflow.com/questions/22948017/is-there-a-way-to-configure-nginx-to-broadcast-incoming-requests-to-multiple-ups – Alex Moore-Niemi Nov 21 '20 at 17:58