Serega
Serialize exactly what was asked. Load exactly what is needed.
{!GitHub Actions}[github.com/andreyruby/serega/actions/workflows/main.yml]
100%
dependencies
>= 3.3
Serega is a Ruby serializer that turns your objects into Hashes ready for JSON. Clients choose the fields they need, and Serega loads only the data those fields use โ in a few queries, with no N+1.
-
โก Fast โ serialization code is generated per field selection and cached. See benchmarks.
-
๐ฏ Clients choose fields โ
?fields=name,posts(title)works out of the box, nested at any depth. -
๐งบ No N+1 โ associations are preloaded and batch loaders run once per relation, only for the requested fields.
-
๐ชถ No dependencies โ plain Ruby, works with Rails, Hanami, Roda, Sinatra or no framework at all.
Show me
class AppSerializer < Serega plugin :activerecord_preloads # preloads associations used by requested fields config.auto_preload = true config.hide_by_default = :auto # fields that need extra queries are sent on request end class UserSerializer < AppSerializer attribute :name attribute :posts, serializer: "PostSerializer" end class PostSerializer < AppSerializer batch :comments_count, ->(posts) { Comment.where(post: posts).group(:post_id).count } attribute :title attribute :comments_count, batch: true end UserSerializer.to_h(User.all) # => [{name: "Bruce Wayne"}, ...] 1 query UserSerializer.to_h(User.all, only: "name,posts(title,comments_count)") # => [{name: "Bruce Wayne", posts: [{title: "Gotham at night", comments_count: 12}, ...]}, ...] # 3 queries, for any number of users
Installation
bundle add serega
Quick start
Define a base serializer with the setup your app uses. Every serializer inherits it.
# app/serializers/app_serializer.rb class AppSerializer < Serega plugin :activerecord_preloads config.auto_preload = true end # app/serializers/user_serializer.rb class UserSerializer < AppSerializer attribute :id attribute :name attribute :email, value: proc { |user, ctx| user.email if user == ctx[:current_user] } attribute :avatar_url, hide: true end # app/controllers/users_controller.rb class UsersController < ApplicationController def index users = UserSerializer.to_json( User.all, only: params[:fields], # "id,name" from GET /users?fields=id,name context: {current_user: current_user} ) render json: users end end
Benchmarks
Serega is on par with the fastest Ruby serializers in speed and allocations, and in some cases beats them. Results, the details of each case and how to run them: benchmarks/README.md.
Features
Select fields
only, except and with accept Symbols, Arrays, Hashes or a string like "name,posts(title)". Unknown fields raise Serega::AttributeNotExist.
UserSerializer.to_h(user, only: [:name, {posts: [:title]}]) UserSerializer.to_h(user, except: :email) UserSerializer.to_h(user, with: :avatar_url) # adds hidden fields
Batch loading
Load data for all serialized objects with one call.
class UserSerializer < AppSerializer batch :followers_count, ->(users) { Follow.where(user: users).group(:user_id).count } attribute :followers_count, batch: true end
โ Batch loading guide ยทPreloads guide
Formatters
Format dates, money and other values the same way everywhere.
class AppSerializer < Serega formatter :iso8601, [:iso8601, 3], allow_nil: true end class UserSerializer < AppSerializer attribute :created_at, format: :iso8601 end
โ Formatters guide
Hashes, Structs and Data
Serialize Hash records, and get results as Struct or Data objects.
class EventSerializer < Serega attribute :title, hash_access: true # reads event[:title] end UserSerializer.to_h(user) # => {name: "Bruce Wayne"} UserSerializer.to_struct(user) # => #<struct name="Bruce Wayne"> UserSerializer.to_data(user) # => #<data name="Bruce Wayne">
โ Hash records guide ยทSerializing guide
Ractors
Serialize in parallel Ractors.
class UserSerializer < Serega attribute :name make_shareable! end Ractor.new(user) { |user| UserSerializer.to_h(user) }.value
โ Ractors guide
And more
-
Attributes โ all attribute options, relations and nested serializers
-
Conditional attributes โ
if:,unless:,if_value:,unless_value: -
Context โ pass
current_userand other request data -
Presenter โ write computed attributes as methods
-
Prepare initial objects โ serialize records by ids
-
Configuration โ all config options
-
Root key and metadata โ wrap results in
{data: ...}and add metadata
Documentation
-
๐ Cheatsheet โ every option on one page
-
๐ Guides โ each feature in depth
-
๐ Documentation site โ guides and API reference
-
๐ค Type signatures โ RBS of the public API
-
๐ Changelog
Development
bundle install bundle exec rake # tests and linter bin/console # irb with serega loaded
Releasing: RELEASE.md.
Contributing
Bug reports, pull requests and ideas are welcome!
License
The gem is available as open source under the terms of the MIT License.