How To Send Secure API Responses with MongoDB
MongoDB is special among other databases in that it uses _id
instead of id
. Let's suppose we are in a scenario where we have a microservices application and one service uses MySQL database and another service uses MongoDB database. Getting JSON responses from both of them will be inconsistent because they both store the IDs differently, and that will make consuming the API unexpected.
Let's see together how we can solve this problem and modify the response of MongoDB to return id
instead of _id
in a centralized location in our codebase.
Transforming _id
to id
not only will make the responses consistent, but also secure because it doesn't tell the client what database we are using in the backend which prevents any exploitation of known MongoDB vulnerabilities.
Modern APIs return JSON objects as responses. So as a quick reminder on how JavaScript turns object literals into JSON objects:
toJSON()
and it gets invoked every time we call JSON.stringify()
.So to modify the returned JSON, we simply have to modify the toJSON()
method attached to that object. Let's see that by pasting this code in your console:
const obj = { name: 'mark', toJSON() { return 2 } }
JSON.stringify(obj)
Similar logic is applied inside mongoose. In a Mongoose schema, we can define a property called toJSON()
that works similarly to JavaScript version. Let's see it in action:
const userSchema = new mongoose.Schema(
{
email: String,
password: String,
},
{
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
delete ret.password;
},
versionKey: false,
},
}
);
In Mongoose, the toJSON
is a property that accepts a method called transform()
that is responsible to transform the document before returning it. To do that, all we have to do is to modify the returned object ret
in place. From the code above, you see I removed the password
property and defined a new id
property.
That's it! It's that easy to make our API responses consistent and secure.