Search code examples
ruby-on-railsrubyapiactive-model-serializersjson-api

Rails API Design: best way to include other attributes with json_api relationships


I have a Rails 5 app in which I use the gem active_model_serializers(https://github.com/rails-api/active_model_serializers). In my app I have a simplified data model that looks something like this:

# LocalizedString.rb
has_many :translations

# Translation.rb
belongs_to :localized_string

I'm trying to follow the best practices from JSON API, I have configured active_model_serializers like this:

ActiveModelSerializers.config.adapter = :json_api

When a user of the API requests translations (http://[root]/api/apps/117/translations) I currently get the following result:

{
  "data": [
    {
      "id": "152",
      "type": "translations",
      "attributes": {
        "value": "Test",
      },
      "relationships": {
        "language": {
          "data": {
            "id": "1",
            "type": "languages"
          }
        },
        "localized-string": {
          "data": {
            "id": "162",
            "type": "localized-strings"
          }
        }
      }
    },
    [...]

From my localised-string I also want to include another attribute that is critical for the consumer of the API, and I don't want to have to make another API call to get the value of the attribute. I wonder what is the best / recommended way to do this that also follows json_api if possible.

Something like this could work:

"localized-string": {
  "data": {
    "id": "162",
    "key": "my key value", # the attribute I need.
    "type": "localized-strings"
  }
}

But I'm not sure how to achieve that using active_model_serializers or if it is another recommended way of doing what I want with [json_api][1].

For completion, my relevant serialiser files looks lik this:

class TranslationSerializer < ActiveModel::Serializer
  attributes :id, :value, :created_at, :updated_at

  has_one :language
  has_one :localized_string, serializer: LocalizedStringParentSerializer
end

class LocalizedStringParentSerializer < ActiveModel::Serializer
  # I want to include the key attribute in my relationship object, but this doesn't work. 
  attributes :id, :key
end

So, any ideas on what I need to do to achieve what I want?


Solution

  • Per spec, relationships are represented by resource object identifiers. To include more than just the id and type, you'll want to use the include param. In AMS, I think that would be 'include: [:localizations], fields: { localizations: [:key]}' (not at computer now, but is approx right)