Consistency is vital, and this is especially true in programming. Data must be in a specific format across an Application. Or perhaps, you may even want to mask some sensitive data contained in an object when passing it to another part of the Application. And, more than likely, this will take place in multiple parts of your Application. JavaScript allows you to customize how JSON.stringify()
handles your objects, making these issues easy to address in a DRY fashion.
An Example Object
Consider the following user
object:
const user = { _id: "68543f312a32568b32186e", username: "jsmith", password: "$2a10somehashedpassword.withsalt", email: "jsmith@smithandco.com" }
If we want to send this user
object to, say, the front-end, there’s a couple of issues that we should address.
The first and most apparent is that we never want to send a password – even a hashed password – to the front-end. Or any other sensitive information, for that fact.
The second problem we face is with the _id
property. This particular naming convention for a unique ID is specific to MongoDB, where a database such as MySQL or PostgreSQL will expect just id
. Since MongoDB is the outlier here, it may be better for us to change the property name when sending the object to the front-end.
The toJSON Function
JavaScript makes customizing how this object is represented by JSON.stringify()
very easy. All we have to do is add a function to the object called toJSON
:
const user = { _id: "68543f312a32568b32186e", username: "jsmith", password: "$2a10somehashedpassword.withsalt", email: "jsmith@smithandco.com", toJSON: function () { return { id: this._id, username: this.username, email: this.email } } } }
By default, when passing an object to JSON.stringify()
, it will look for the toJSON
function, and use the value returned by it. Above, we are returning an object representing this user
. We have changed _id
to id
, and also removed the password from the equation altogether. Mission accomplished! Our user
is now in a standard format, with sensitive information hidden.
For more on how to customize JSON.stringify()
using toJSON
, see the official Mozilla documentation here.
Bonus: Mongoose JS Schema and toJSON
Let’s say that our user
object were instead a Schema
in Mongoose:
//... const userSchema = new Schema( { username: { type: String, required: true }, password: { type: String, required: true }, email: { type: String, required: true } } );
Mongoose provides a way for us to define the handling of documents when converting them to JSON. What we need to do is add a toJSON
option Object to the Schema
, which will contain function named transform
. This function will look a little different than what we saw previously but will act much the same.
//... const userSchema = new Schema( { username: { type: String, required: true }, password: { type: String, required: true }, email: { type: String, required: true } }, // --- Options object here -- // { toJSON: { // doc -- the Mongoose document being converted // ret -- the plain object which has been converted transform(doc, ret) { // First add the id property to the object being returned ret.id = ret._id; // Then delete the _id property from the object being returned delete ret._id; // Also delete the password, to make sure it is hidden delete ret.password; } } } );
The above looks a lot different from what we saw before but acts much the same. Previously, we were returning an Object to represent how we wanted to display the information. Now, in Mongoose, it is more of a ‘before and after’ scenario. We are defining a function with two parameters – the original document (doc
), and the Object representation of the document to be returned (ret
). To change the representation of the Object in JSON, we make direct modifications to the ret
Object.
Check out the official Mongoose documentation for more info on the toJSON
option.