-
Notifications
You must be signed in to change notification settings - Fork 21
JSON Serialization
A stitches-based microservice is designed to be as Rails-like as possible, which means that your initial implementation of any API is to expose the underlying resource the way Rails defaults to encoding it in JSON, i.e. to_json
.
This prevents your controller from having to build up a customized hash, or from having to remember to use a thid party library. JSON serialization can be slow, but it's unlikely to be a bottleneck as you build your service, and it's also not a foregone conclusion that making your endpoint faster requires fancier JSON serialization.
The Rails Doctrine says Convention over Configuration, and the convention is Rails (and thus stitches) is to use Rails' default JSON serialization.
You may want to customize it. Some developers have a strong distaste for exposing database primary keys, or you may have data that you need to keep private to give your API a smaller surface area. You may also wish to include a nested object.
All of these use-cases can be served by Rails default serialization mechanism, which boils down to the method serializable_hash
.
Suppose we have a Person
object that contains an id
, name
, email
, encrypted_password
, created_at
, and updated_at
. Suppose further that a person has an instance of EmailPreferences
that contains an id
, marketing_opt_in
, created_at
, and updated_at
.
We want to expose a structure like so:
{
"name": "Chris Jones",
"email": "[email protected]",
"signed_up_on": "2018-01-03",
"email_preferences": {
"marketing_opt_in": true,
"updated_at": "2018-03-02 12:34:15 -0000"
}
}
This:
- omits several fields
- uses a derived field
signed_up_on
- has a nested object
- that itself omits some fields
You might decide you need Fancy Serialization™ or Hand-Crafted Hashes™ to do this. You don't! Rails has this.
class Person
def signed_up_on
self.created_at.to_date
end
def serializable_hash(options = {})
super(options.merge({
only: [ :name, :email ],
methods: [ :signed_up_on, :email_preferences ],
}))
end
end
class EmailPreferences
def serializable_hash(options = {})
super(options.merge({
only: [ :marketing_opt_in, :updated_at ]
}))
end
end
When you do this, anywhere you serialize a Person
, you'll get the same structure, which is generally what you want. This is most handy if your service sends messages - the messages will have the same structure as your API.