Foca Granola Versions Save

Simple JSON serializers (Cereal-izers. GET IT?)

v1.0.0

7 years ago

After a couple months of production use without any bugs, and with the stable API finalized in v0.13, I'm confident to finally release v1.0. πŸŽ‰ πŸŽ‰ πŸŽ‰

This has been a long time coming, with over 2 years of work to make sure we can have the smallest and fastest ruby library to give some structure around serializing responses from your API.

Many thanks go to everyone who contributed with feedback, comments, guidance, or code. ❀️ πŸ’œ πŸ’™ πŸ’š πŸ’›

Deprecations

  • Removed all methods deprecated in v0.13.0

Happy serializing! πŸŽ‰

giphy

v0.13.0

7 years ago

We keep getting closer to v1.0. This release is mostly improvements to allow plugins to integrate better with Granola, and formalizing the APIs we want to have.

Improvements

  • Introduce Renderer objects. These wrap around the rendering callable. Add a couple methods around the renderer registration:

    Granola.render :json, via: Oj.method(:dump),
                          content_type: "application/json"
    Granola.render :yaml, via: YAML.method(:dump),
                          content_type: "text/x-yaml"
    
    # List all registered rendering formats
    Granola.renderable_formats #=> [:json, :yaml]
    
    # Get a Renderer object
    json_renderer = Granola.renderer(:json)
    json_renderer.content_type #=> "application/json"
    json_renderer.render(a_serializer) #=> JSON stream
    
  • In the Rack helper, automatically choose the best rendering format based on a request's Accept header. (https://github.com/foca/granola/pull/14)

  • Allow customizing how we lookup constants when finding a serializer class for a given object.

    Granola::Util.constant_lookup = API.method(:const_get)
    Granola::Util.serializer_class_for(User.new) #=> API::UserSerializer (or NameError)
    
  • Add ruby 2.3's frozen string literal magic comments everywhere. This should give us a small performance boost.

  • Allow passing an env Hash manually to the Rack helper, for contexts where we don't have access an env method. Background: Rails 5.1 will deprecate ActionController::Metal#env in favor of using the Request object.

Bug Fixes

  • Serialize Hashes as primitive types in the Rack helper. This should work:

    errors = { error: "Everything is terrible"  }
    granola(errors, status: 400)
    

Deprecations

As we move closer to finalizing the public API, we're getting rid of a few methods that will be gone in 1.0:

  • Granola::RENDERERS. This constant is effectively private now, and shouldn't be accessed. Use Granola.renderable_formats and Granola.renderer instead.
  • Granola::Serializer#mime_type(format) has been deprecated in favor of Granola.renderer(format).content_type. Serializers shouldn't know about content types.
  • Granola::Serializer#render(format) has been deprecated in favor of Granola.renderer(format).render(serializer). Rendering to a particular format is, again, orthogonal to a Serializer's responsibility, which is defining the structure something takes when serialized.

Happy serializing! πŸŽ‰

v0.11.0

7 years ago

We're getting closer and closer to v1.0.0! In the meantime, here's another intermediate release with some improvements.

Breaking changes

The old Granola.json = callable is deprecated (and will be gone in v1.0). Now you can register any rendering mechanism (JSON or other formats) like so:

Granola.render :json, via: JSON.method(:generate), content_type: "application/json"

If you want your serializers to be renderable into other formats, just register them via Granola.render. They all work the same now πŸ˜„

You can find the full rationale behind this change in the original pull request.

Performance Improvements

Minor improvements

  • The benchmarks have been improved, and include a comparison against ActiveModelSerializers now.

Enjoy!

v0.10.0

9 years ago

After v0.9.0 I was pointed out that Serializer#serialized was a pretty bad name for the thing that has not yet been serialized. :stuck_out_tongue_winking_eye:

Pretty fair. So last backwards-incompatible change before we reach 1.0: The method is now #data:

class UserSerializer < Granola::Serializer
  def data
    {
      "name" => object.name,
      "email" => object.email,
      "age" => object.age,
    }
  end
end

Thanks @pote for the feedback, and @soveran for the name suggestion :sparkling_heart:

v0.9.0

9 years ago

This marks the last general release before we release 1.0 :tada: :tada: :tada:

The API should be considered stable and public. Basically, it shouldn't change after this release. The notable changes are:

These changes are backwards-incompatible :boom:

  • Serializer#attributes was renamed to Serializer#serialized. See commit.
  • The rack helper is now called #granola. So in Cuba you'd do: halt granola(current_user, with: SessionSerializer), for example. Thanks @djanowski for the idea :blue_heart: See commit.
  • Granola::Rack no longer cares about checking freshness of a response. Instead, it makes the body defer to the call to each before actually calling #to_json. This means that you can put Rack::ConditionalGet in the middleware stack and use that to make the response 304 to clients. See commit.

These are backwards-compatible :ok_hand:

  • Allow passing default headers to the rack helper. Thank @lucasefe for this one :purple_heart:. See commit.
  • Don't hate so much on MultiJson :heart: As @luislavena put it, the performance problems alluded to in v0.0.4 have been fixed. We still default to our own way of configuring the JSON backend, but if MultiJson is available then we use that. See commit.
  • Open the road for multiple formats (such as serializing to YAML or MsgPack right from Granola). The rack helper now includes an as: keyword that specifies the format to render (defaults to :json). As long as you define Serializer::MIME_TYPES[format] and a #to_#{format} method in your serializers, then you can just granola(object, as: <format>). See commit

Thanks to everyone who offered suggestions and feedback for making this possible. I :heartpulse: you.

v0.0.4

9 years ago

Don't depend on MultiJson, as it doesn't help performance-wise and it's easy to swap the JSON backend anyway. For example, if you were to change to Yajl:

require "yajl"
Granola.json = ->(obj, **opts) { Yajl::Encoder.encode(obj, opts) }

See https://github.com/foca/granola/issues/1 for context.

:heart: :heart: :heart: Thanks @djanowski and @guilleiguaran for bringing this up! :heart: :heart: :heart:

v0.0.3

9 years ago

A couple bugs squashed. Getting there!

v0.0.2

9 years ago

Cleaning up the API a bit so it's more flexible and simpler to use. Still… use it at your own risk.

v0.0.1

9 years ago

This code isn't production ready, but feel free to play around with it.