3

I've been looking around for the easiest solution to convert all Datetime values to ISO 8601 when sending them to a specific requester from an API. I was able to monkey patch Time#to_json with the following:

class Time
  def to_json(options = {})
    self.iso8601.to_json
  end
end

And require the file in the before callback of Grape when params showed the request was coming from the desired location.

Is this the best way to accomplish this? Could I instead be doing something in the after callback of Grape to loop through my data and convert the values there? Monkey patching Time#to_json gets the job done, but feels funny to me. Though I am new to Ruby.

Maaack
  • 115
  • 10
  • Your instincts are good. Monkey patching classes should only be used as a last resort. In your case I think it's a bad idea because who knows where else in the program the default behavior might be relied upon -- and if not now, maybe in the future. You can add this message to individual Time instances if you can figure out which instances need modifying. – Keith Bennett May 31 '16 at 07:09
  • Where are your `Time` instances coming from? What do you use as a backend? Could you create a wrapper (presenter) class for `Time` and use that instead? – Mladen Jablanović May 31 '16 at 07:48

1 Answers1

2

Are you using Grape Entity to expose your models? If you're using it then you can define a reusable formatter like this:

module ApiHelpers
  extend Grape::API::Helpers

  Grape::Entity.format_with :iso8601 do |date|
    date.iso8601 if date
  end
end

Then, you can use this formatter in all your entities:

module Entities
  class MyModel < Grape::Entity
    expose :updated_at, format_with: :iso8601
  end

  class AnotherModel < Grape::Entity
    expose :created_at, format_with: :iso8601
  end
end

But if you're not using Grape Entity... well, I think you should. :)

PS.: All examples I showed here were extracted from Grape Entity documentation. https://github.com/ruby-grape/grape-entity

Marlon
  • 888
  • 6
  • 12
  • Hi, not currently using Grape Entity, but I did look at it some. I need more arguments in favor of it, as just solving this problem isn't reason enough to invest the time to transition. – Maaack May 31 '16 at 16:26
  • 1
    First off, I think you should always shield your API from possible changes in your Models and vice-versa. Also, remember that what you expose through a Rest API are "Resources" and not Models. In fact, a resource can even be a combination of multiple Models. Entities allow you to define a Resource and reuse it whenever you need it. Using entities, you can exclude fields, create fields that are a combination of others fields. In a nutshell, it gives you flexibility. – Marlon May 31 '16 at 17:06