MapMyMind MapMyMind - 1 year ago 135
Node.js Question

Rest API Node Js & Express, create link(href) to self

Currently I'm working on a REST API in Node JS & Express. I have to create a link for every resource in the API like the example beyond.

{
"id": "20281",
"title": "test",
"body": "test",
"date": "2017-11-14 09:01:35",
"_links": {
"self": {
"href": "https://docent.cmi.hro.nl/bootb/demo/notes/20281"
},
"collection": {
"href": "https://docent.cmi.hro.nl/bootb/demo/notes/"
}
}
},


I know I can handle this in my controller because the req object is available. But it would be better to create a virtual field in my model to create the link on the fly and not save it in the DB.

What would be the best way to do this?

DB: MongoDB
ODM: Mongoose

Answer Source

There are a lot of ways to do this, and you haven't described your DB or ORM or the like, but implied that you have something along those lines with your terminology.

The simplest thing to do would be to just assume that this is not a concern of the storage, but instead it's something that you'd apply globally to the api, so that all routes have it applied. This could be in the form of middleware:

router.use((req, res, next) => {
  if (res.data) { // if you do it this way, none of your routes will actually do a res.send, but instead will put their data into res.data and rely on another middleware to render or send it
     res.data._links = {
       self: calculateSelf(req, res.data),
       collection: calculateCollection(req, res.data)
     };
  }
});

Given that, those two link calculators could use some standard patterns or regex to figure out what the link should look like generically.

Alternatively, if you're using Mongoose, you could override toJSON to populate those links in any models you expect to send down the wire, but that implies that your models should be aware of what the root application URL is, which I don't recommend.

Virtual field implementation:

YourSchema.virtual('links').get(() => {
  return {
    self: 'http://example.com/api/v1.0/schema/' + this._id,
    collection: 'http://example.com/api/v1.0/schema/'
  };
});

For that to work, you have to pass { virtuals: true } to toObject() or toJSON() or set it as a global mongoose configuration to always show virtuals. As I said before, though, I really wouldn't recommend that as it requires the schemas to have access to and knowledge of the base URL, which can change between environments. If (as your schema implies) the model is representing a web page, then the URL template could be something that is actually relevant to the model, but in most domains that wouldn't be the case and so I'd recommend the middleware approach.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download