Search code examples
ruby-on-railsrubyjsonactive-model-serializers

How to standardize JSON results of Rails project


I need to add extra tags to JSON results of Rails project.

GET /menus

{
  meta: {
    code: 200,
    message: ""
  }
  data: [
     // default rails response goes here
  ]
}

I don't want to do something like this in the controllers:

render json: { meta: { code: 200, message: ''}, data: @store.menus }

I looked in active_model_serializers gem, but didn't find any option that provides this type of customization.


Solution

  • You could create a JsonResponse class to act as a view model to wrap the data you want to send back:

    class JsonResponse
      attr_accessor :status, :message, :data
    
      STATUS_SUCCESS = 200;
      STATUS_CREATED = 201;
      STATUS_NOT_FOUND = 404;
    
      def self.success(data, message = nil)
        self.new(STATUS_SUCCESS, message || "OK", data)
      end
    
      def self.created(data, message = nil)
        self.new(STATUS_CREATED, message || "CREATED", data)
      end
    
      def self.not_found(data = nil, message = nil)
        self.new(STATUS_NOT_FOUND, message || "NOT FOUND", data)
      end
    
      def initialize(status = 200, message = "", data = nil)
        @status = status
        @message = message
        @data = data
      end
    
      def to_hash
        {
          meta: {
            code: status,
            message: message || ""
          },
          data: data.is_a?(Hash) ? data : data.to_hash
        }
      end
    end
    

    This gives you several ways of using this:

    # One-liners
    render json: JsonResponse.new(JsonResponse::STATUS_SUCCESS, nil, @store.menus).to_hash
    render json: JsonResponse.success(@store.menus).to_hash
    render json: JsonResponse.created(@store).to_hash
    render json: JsonResponse.not_found.to_hash
    
    # Multi-liners
    response = JsonResponse.new JsonResponse::STATUS_SUCCESS, nil, @store.menus
    response = JsonResponse.success @store.menus
    response = JsonResponse.created @store
    response = JsonResponse.not_found
    
    # Render the JSON view
    render json: response.to_hash