{"id":15412567,"url":"https://github.com/elmassimo/oj_serializers","last_synced_at":"2025-04-05T18:10:56.858Z","repository":{"id":45514207,"uuid":"291487803","full_name":"ElMassimo/oj_serializers","owner":"ElMassimo","description":"⚡️ Faster JSON serialization for Ruby on Rails. Easily migrate away from Active Model Serializers.","archived":false,"fork":false,"pushed_at":"2023-10-22T17:39:45.000Z","size":204,"stargazers_count":132,"open_issues_count":7,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-29T17:11:35.456Z","etag":null,"topics":["json","json-serialization","oj","performance","ruby","serialization","serializer"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ElMassimo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-08-30T14:36:44.000Z","updated_at":"2025-03-05T15:47:28.000Z","dependencies_parsed_at":"2024-01-13T20:43:25.275Z","dependency_job_id":"a05f24f2-930e-4e28-b612-0e157ee8ab0a","html_url":"https://github.com/ElMassimo/oj_serializers","commit_stats":{"total_commits":24,"total_committers":1,"mean_commits":24.0,"dds":0.0,"last_synced_commit":"39ef42a28357d0f024af32829b28bcfe017f8c6b"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Foj_serializers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Foj_serializers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Foj_serializers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Foj_serializers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ElMassimo","download_url":"https://codeload.github.com/ElMassimo/oj_serializers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247378149,"owners_count":20929297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","json-serialization","oj","performance","ruby","serialization","serializer"],"created_at":"2024-10-01T16:53:44.512Z","updated_at":"2025-04-05T18:10:56.839Z","avatar_url":"https://github.com/ElMassimo.png","language":"Ruby","readme":"\u003ch1 align=\"center\"\u003e\nOj Serializers\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/ElMassimo/oj_serializers/actions\"\u003e\u003cimg alt=\"Build Status\" src=\"https://github.com/ElMassimo/oj_serializers/workflows/build/badge.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://codeclimate.com/github/ElMassimo/oj_serializers\"\u003e\u003cimg alt=\"Maintainability\" src=\"https://codeclimate.com/github/ElMassimo/oj_serializers/badges/gpa.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://codeclimate.com/github/ElMassimo/oj_serializers\"\u003e\u003cimg alt=\"Test Coverage\" src=\"https://codeclimate.com/github/ElMassimo/oj_serializers/badges/coverage.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://rubygems.org/gems/oj_serializers\"\u003e\u003cimg alt=\"Gem Version\" src=\"https://img.shields.io/gem/v/oj_serializers.svg?colorB=e9573f\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/ElMassimo/oj_serializers/blob/main/LICENSE.txt\"\u003e\u003cimg alt=\"License\" src=\"https://img.shields.io/badge/license-MIT-428F7E.svg\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003c/h1\u003e\n\nFaster JSON serializers for Ruby, built on top of the powerful [`oj`][oj] library.\n\n[oj]: https://github.com/ohler55/oj\n[mongoid]: https://github.com/mongodb/mongoid\n[ams]: https://github.com/rails-api/active_model_serializers\n[jsonapi]: https://github.com/jsonapi-serializer/jsonapi-serializer\n[panko]: https://github.com/panko-serializer/panko_serializer\n[blueprinter]: https://github.com/procore/blueprinter\n[benchmarks]: https://github.com/ElMassimo/oj_serializers/tree/master/benchmarks\n[raw_benchmarks]: https://github.com/ElMassimo/oj_serializers/blob/main/benchmarks/document_benchmark.rb\n[sugar]: https://github.com/ElMassimo/oj_serializers/blob/main/lib/oj_serializers/sugar.rb#L14\n[migration guide]: https://github.com/ElMassimo/oj_serializers/blob/main/MIGRATION_GUIDE.md\n[design]: https://github.com/ElMassimo/oj_serializers#design-\n[associations]: https://github.com/ElMassimo/oj_serializers#associations-\n[compose]: https://github.com/ElMassimo/oj_serializers#composing-serializers-\n[raw_json]: https://github.com/ohler55/oj/issues/542\n[trailing_commas]: https://maximomussini.com/posts/trailing-commas/\n[render dsl]: https://github.com/ElMassimo/oj_serializers#render-dsl-\n[sorbet]: https://sorbet.org/\n[Discussion]: https://github.com/ElMassimo/oj_serializers/discussions\n[TypeScript]: https://www.typescriptlang.org/\n[types_from_serializers]: https://github.com/ElMassimo/types_from_serializers\n[inheritance]: https://github.com/ElMassimo/types_from_serializers/blob/main/playground/vanilla/app/serializers/song_with_videos_serializer.rb#L1\n\n## Why? 🤔\n\n[`ActiveModel::Serializer`][ams] has a nice DSL, but it allocates many objects\nleading to memory bloat, time spent on GC, and lower performance.\n\n`Oj::Serializer` provides a similar API, with [better performance][benchmarks].\n\nLearn more about [how this library achieves its performance][design].\n\n## Features ⚡️\n\n- Intuitive declaration syntax, supporting mixins and inheritance\n- Reduced [memory allocation][benchmarks] and [improved performance][benchmarks]\n- Generate [TypeScript interfaces automatically][types_from_serializers]\n- Support for [`has_one`][associations] and [`has_many`][associations], compose with [`flat_one`][compose]\n- Useful development checks to avoid typos and mistakes\n- [Migrate easily from Active Model Serializers][migration guide]\n\n## Installation 💿\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'oj_serializers'\n```\n\nAnd then run:\n\n    $ bundle install\n\n## Usage 🚀\n\nYou can define a serializer by subclassing `Oj::Serializer`, and specify which\nattributes should be serialized.\n\n```ruby\nclass AlbumSerializer \u003c Oj::Serializer\n  attributes :name, :genres\n\n  attribute :release do\n    album.release_date.strftime('%B %d, %Y')\n  end\n\n  has_many :songs, serializer: SongSerializer\nend\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample Output\u003c/summary\u003e\n\n```ruby\n{\n  name: \"Abraxas\",\n  genres: [\n    \"Pyschodelic Rock\",\n    \"Blues Rock\",\n    \"Jazz Fusion\",\n    \"Latin Rock\",\n  ],\n  release: \"September 23, 1970\",\n  songs: [\n    {\n      track: 1,\n      name: \"Sing Winds, Crying Beasts\",\n      composers: [\"Michael Carabello\"],\n    },\n    {\n      track: 2,\n      name: \"Black Magic Woman / Gypsy Queen\",\n      composers: [\"Peter Green\", \"Gábor Szabó\"],\n    },\n    {\n      track: 3,\n      name: \"Oye como va\",\n      composers: [\"Tito Puente\"],\n    },\n    {\n      track: 4,\n      name: \"Incident at Neshabur\",\n      composers: [\"Alberto Gianquinto\", \"Carlos Santana\"],\n    },\n    {\n      track: 5,\n      name: \"Se acabó\",\n      composers: [\"José Areas\"],\n    },\n    {\n      track: 6,\n      name: \"Mother's Daughter\",\n      composers: [\"Gregg Rolie\"],\n    },\n    {\n      track: 7,\n      name: \"Samba pa ti\",\n      composers: [\"Santana\"],\n    },\n    {\n      track: 8,\n      name: \"Hope You're Feeling Better\",\n      composers: [\"Rolie\"],\n    },\n    {\n      track: 9,\n      name: \"El Nicoya\",\n      composers: [\"Areas\"],\n    },\n  ],\n}\n```\n\u003c/details\u003e\n\nYou can then use your new serializer to render an object or collection:\n\n```ruby\nclass AlbumsController \u003c ApplicationController\n  def show\n    render json: AlbumSerializer.one(album)\n  end\n\n  def index\n    render json: { albums: AlbumSerializer.many(albums) }\n  end\nend\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eActive Model Serializers style\u003c/summary\u003e\n\n```ruby\nrequire \"oj_serializers/sugar\" # In an initializer\n\nclass AlbumsController \u003c ApplicationController\n  def show\n    render json: album, serializer: AlbumSerializer\n  end\n  \n  def index\n    render json: albums, root: :albums, each_serializer: AlbumSerializer\n  end\nend\n```\n\u003c/details\u003e\n\n## Rendering 🖨\n\nUse `one` to serialize objects, and `many` to serialize enumerables:\n\n```ruby\nrender json: {\n  favorite_album: AlbumSerializer.one(album),\n  purchased_albums: AlbumSerializer.many(albums),\n}\n```\n\nSerializers can be rendered arrays, hashes, or even inside `ActiveModel::Serializer`\nby using a method in the serializer, making it very easy to combine with other\nlibraries and migrate incrementally.\n\n`render` is a shortcut for `one` and `many`:\n\n```ruby\nrender json: {\n  favorite_album: AlbumSerializer.render(album),\n  purchased_albums: AlbumSerializer.render(albums),\n}\n```\n\n## Attributes DSL 🪄\n\nSpecify which attributes should be rendered by calling a method in the object to serialize.\n\n```ruby\nclass PlayerSerializer \u003c Oj::Serializer\n  attributes :first_name, :last_name, :full_name\nend\n```\n\nYou can serialize custom values by specifying that a method is an `attribute`:\n\n```ruby\nclass PlayerSerializer \u003c Oj::Serializer\n  attribute :name do\n    \"#{player.first_name} #{player.last_name}\"\n  end\n\n  # or\n\n  attribute\n  def name\n    \"#{player.first_name} #{player.last_name}\"\n  end\nend\n```\n\n\u003e **Note**\n\u003e\n\u003e In this example, `player` was inferred from `PlayerSerializer`.\n\u003e\n\u003e You can customize this by using [`object_as`](#using-a-different-alias-for-the-internal-object).\n\n\n### Associations 🔗\n\nUse `has_one` to serialize individual objects, and `has_many` to serialize a collection.\n\nYou must specificy which serializer to use with the `serializer` option.\n\n```ruby\nclass SongSerializer \u003c Oj::Serializer\n  has_one :album, serializer: AlbumSerializer\n  has_many :composers, serializer: ComposerSerializer\nend\n```\n\nSpecify a different value for the association by providing a block:\n\n```ruby\nclass SongSerializer \u003c Oj::Serializer\n  has_one :album, serializer: AlbumSerializer do\n    Album.find_by(song_ids: song.id)\n  end\nend\n```\n\nIn case you need to pass options, you can call the serializer manually:\n\n```ruby\nclass SongSerializer \u003c Oj::Serializer\n  attribute :album do\n    AlbumSerializer.one(song.album, for_song: song)\n  end\nend\n```\n\n### Aliasing or renaming attributes ↔️\n\nYou can pass `as` when defining an attribute or association to serialize it\nusing a different key:\n\n```ruby\nclass SongSerializer \u003c Oj::Serializer\n  has_one :album, as: :first_release, serializer: AlbumSerializer\n\n  attributes title: {as: :name}\n\n  # or as a shortcut\n  attributes title: :name\nend\n```\n\n### Conditional attributes ❔\n\nYou can render attributes and associations conditionally by using `:if`.\n\n```ruby\nclass PlayerSerializer \u003c Oj::Serializer\n  attributes :first_name, :last_name, if: -\u003e { player.display_name? }\n\n  has_one :album, serializer: AlbumSerializer, if: -\u003e { player.album }\nend\n```\n\nThis is useful in cases where you don't want to `null` values to be in the response.\n\n## Advanced Usage 🧙‍♂️\n\n### Using a different alias for the internal object\n\nIn most cases, the default alias for the `object` will be convenient enough.\n\nHowever, if you would like to specify it manually, use `object_as`:\n\n```ruby\nclass DiscographySerializer \u003c Oj::Serializer\n  object_as :artist\n\n  # Now we can use `artist` instead of `object` or `discography`.\n  attribute\n  def latest_albums\n    artist.albums.desc(:year)\n  end\nend\n```\n\n### Identifier attributes\n\nThe `identifier` method allows you to only include an identifier if the record\nor document has been persisted.\n\n```ruby\nclass AlbumSerializer \u003c Oj::Serializer\n  identifier\n\n  # or if it's a different field\n  identifier :uuid\nend\n```\n\nAdditionally, identifier fields are always rendered first, even when sorting\nfields alphabetically.\n\n### Transforming attribute keys 🗝\n\nWhen serialized data will be consumed from a client language that has different\nnaming conventions, it can be convenient to transform keys accordingly.\n\nFor example, when rendering an API to be consumed from the browser via JavaScript,\nwhere properties are traditionally named using camel case.\n\nUse `transform_keys` to handle that conversion.\n\n```ruby\nclass BaseSerializer \u003c Oj::Serializer\n  transform_keys :camelize\n\n  # shortcut for\n  transform_keys -\u003e (key) { key.to_s.camelize(:lower) }\nend\n```\n\nThis has no performance impact, as keys will be transformed at load time.\n\n### Sorting attributes 📶\n\nBy default attributes are rendered in the order they are defined.\n\nIf you would like to sort attributes alphabetically, you can specify it at a\nserializer level:\n\n```ruby\nclass BaseSerializer \u003c Oj::Serializer\n  sort_attributes_by :name # or a Proc\nend\n```\n\nThis has no performance impact, as attributes will be sorted at load time.\n\n### Path helpers 🛣\n\nIn case you need to access path helpers in your serializers, you can use the\nfollowing:\n\n```ruby\nclass BaseSerializer \u003c Oj::Serializer\n  include Rails.application.routes.url_helpers\n\n  def default_url_options\n    Rails.application.routes.default_url_options\n  end\nend\n```\n\nOne slight variation that might make it easier to maintain in the long term is\nto use a separate singleton service to provide the url helpers and options, and\nmake it available as `urls`.\n\n### Generating TypeScript automatically 🤖\n\nIt's easy for the backend and the frontend to become out of sync. Traditionally, preventing bugs requires writing extensive integration tests.\n\n[TypeScript] is a great tool to catch this kind of bugs and mistakes, as it can detect incorrect usages and missing fields, but writing types manually is cumbersome, and they can become stale over time, giving a false sense of confidence.\n\n[`types_from_serializers`][types_from_serializers] extends this library to allow embedding type information, as well as inferring types from the SQL schema when available, and uses this information to automatically generate TypeScript interfaces from your serializers.\n\nAs a result, it's posible to easily detect mismatches between the backend and the frontend, as well as make the fields more discoverable and provide great autocompletion in the frontend, without having to manually write the types.\n\n### Composing serializers 🧱\n\nThere are three options to [compose serializers](https://github.com/ElMassimo/oj_serializers/discussions/10#discussioncomment-5523921): [inheritance], mixins, and `flat_one`.\n\nUse `flat_one` to include all attributes from a different serializer:\n\n```ruby\nclass AttachmentSerializer \u003c BaseSerializer\n  identifier\n\n  class BlobSerializer \u003c BaseSerializer\n    attributes :filename, :byte_size, :content_type, :created_at\n  end\n\n  flat_one :blob, serializer: BlobSerializer\nend\n```\n\nThink of it as `has_one` without a \"root\", all the attributes are added directly.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample Output\u003c/summary\u003e\n\n```ruby\n{\n  id: 5,\n  filename: \"image.jpg,\n  byte_size: 256074,\n  content_type: \"image/jpeg\",\n  created_at: \"2022-08-04T17:25:12.637-07:00\",\n}\n```\n\u003c/details\u003e\n\nThis is especially convenient when using [`types_from_serializers`][types_from_serializers],\nas it enables automatic type inference for the included attributes.\n\n### Memoization \u0026 local state\n\nSerializers are designed to be stateless so that an instanced can be reused, but\nsometimes it's convenient to store intermediate calculations.\n\nUse `memo` for memoization and storing temporary information.\n\n```ruby\nclass DownloadSerializer \u003c Oj::Serializer\n  attributes :filename, :size\n\n  attribute\n  def progress\n    \"#{ last_event\u0026.progress || 0 }%\"\n  end\n\nprivate\n\n  def last_event\n    memo.fetch(:last_event) {\n      download.events.desc(:created_at).first\n    }\n  end\nend\n```\n\n### `hash_attributes` 🚀\n\nVery convenient when serializing Hash-like structures, this strategy uses the `[]` operator.\n\n```ruby\nclass PersonSerializer \u003c Oj::Serializer\n  hash_attributes 'first_name', :last_name\nend\n\nPersonSerializer.one('first_name' =\u003e 'Mary', :middle_name =\u003e 'Jane', :last_name =\u003e 'Watson')\n# {first_name: \"Mary\", last_name: \"Watson\"}\n```\n\n### `mongo_attributes` 🚀\n\nReads data directly from `attributes` in a [Mongoid] document.\n\nBy skipping type casting, coercion, and defaults, it [achieves the best performance][raw_benchmarks].\n\nAlthough there are some downsides, depending on how consistent your schema is,\nand which kind of consumer the API has, it can be really powerful.\n\n```ruby\nclass AlbumSerializer \u003c Oj::Serializer\n  mongo_attributes :id, :name\nend\n```\n\n### Caching 📦\n\nUsually rendering is so fast that __turning caching on can be slower__.\n\nHowever, in cases of deeply nested structures, unpredictable query patterns, or\nmethods that take a long time to run, caching can improve performance.\n\nTo enable caching, use `cached`, which calls `cache_key` in the object:\n\n```ruby\nclass CachedUserSerializer \u003c UserSerializer\n  cached\nend\n```\n\nYou can also provide a lambda to `cached_with_key` to define a custom key:\n\n```ruby\nclass CachedUserSerializer \u003c UserSerializer\n  cached_with_key -\u003e(user) {\n    \"#{ user.id }/#{ user.current_sign_in_at }\"\n  }\nend\n```\n\nIt will leverage `fetch_multi` when serializing a collection with `many` or\n`has_many`, to minimize the amount of round trips needed to read and write all\nitems to cache.\n\nThis works specially well if your cache store also supports `write_multi`.\n\n### Writing to JSON\n\nIn some corner cases it might be faster to serialize using a `Oj::StringWriter`,\nwhich you can access by using `one_as_json` and `many_as_json`.\n\nAlternatively, you can toggle this mode at a serializer level by using\n`default_format :json`, or configure it globally from your base serializer:\n\n```ruby\nclass BaseSerializer \u003c Oj::Serializer\n  default_format :json\nend\n```\n\nThis will change the default shortcuts (`render`, `one`, `one_if`, and `many`),\nso that the serializer writes directly to JSON instead of returning a Hash.\n\nEven when using this mode, you can still use rendered values inside arrays,\nhashes, and other serializers, thanks to [the `raw_json` extensions][raw_json].\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample Output\u003c/summary\u003e\n\n```json\n{\n  \"name\": \"Abraxas\",\n  \"genres\": [\n    \"Pyschodelic Rock\",\n    \"Blues Rock\",\n    \"Jazz Fusion\",\n    \"Latin Rock\"\n  ],\n  \"release\": \"September 23, 1970\",\n  \"songs\": [\n    {\n      \"track\": 1,\n      \"name\": \"Sing Winds, Crying Beasts\",\n      \"composers\": [\n        \"Michael Carabello\"\n      ]\n    },\n    {\n      \"track\": 2,\n      \"name\": \"Black Magic Woman / Gypsy Queen\",\n      \"composers\": [\n        \"Peter Green\",\n        \"Gábor Szabó\"\n      ]\n    },\n    {\n      \"track\": 3,\n      \"name\": \"Oye como va\",\n      \"composers\": [\n        \"Tito Puente\"\n      ]\n    },\n    {\n      \"track\": 4,\n      \"name\": \"Incident at Neshabur\",\n      \"composers\": [\n        \"Alberto Gianquinto\",\n        \"Carlos Santana\"\n      ]\n    },\n    {\n      \"track\": 5,\n      \"name\": \"Se acabó\",\n      \"composers\": [\n        \"José Areas\"\n      ]\n    },\n    {\n      \"track\": 6,\n      \"name\": \"Mother's Daughter\",\n      \"composers\": [\n        \"Gregg Rolie\"\n      ]\n    },\n    {\n      \"track\": 7,\n      \"name\": \"Samba pa ti\",\n      \"composers\": [\n        \"Santana\"\n      ]\n    },\n    {\n      \"track\": 8,\n      \"name\": \"Hope You're Feeling Better\",\n      \"composers\": [\n        \"Rolie\"\n      ]\n    },\n    {\n      \"track\": 9,\n      \"name\": \"El Nicoya\",\n      \"composers\": [\n        \"Areas\"\n      ]\n    }\n  ]\n}\n```\n\u003c/details\u003e\n\n## Design 📐\n\nUnlike `ActiveModel::Serializer`, which builds a Hash that then gets encoded to\nJSON, this implementation can use `Oj::StringWriter` to write JSON directly,\ngreatly reducing the overhead of allocating and garbage collecting the hashes.\n\nIt also allocates a single instance per serializer class, which makes it easy\nto use, while keeping memory usage under control.\n\nThe internal design is simple and extensible, and because the library is written\nin Ruby, creating new serialization strategies requires very little code.\nPlease open a [Discussion] if you need help 😃\n\n### Comparison with other libraries\n\n`ActiveModel::Serializer` instantiates one serializer object per item to be serialized.\n\nOther libraries such as [`blueprinter`][blueprinter] [`jsonapi-serializer`][jsonapi]\nevaluate serializers in the context of a `class` instead of an `instance` of a class.\nThe downside is that you can't use instance methods or local memoization, and any\nmixins must be applied to the class itself.\n\n[`panko-serializer`][panko] also uses `Oj::StringWriter`, but it has the big downside of having to own the entire render tree. Putting a serializer inside a Hash or an Active Model Serializer and serializing that to JSON doesn't work, making a gradual migration harder to achieve. Also, it's optimized for Active Record but I needed good Mongoid support.\n\n`Oj::Serializer` combines some of these ideas, by using instances, but reusing them to avoid object allocations. Serializing 10,000 items instantiates a single serializer. Unlike `panko-serializer`, it doesn't suffer from [double encoding problems](https://panko.dev/docs/response-bag) so it's easier to use.\n\nFollow [this discussion][raw_json] to find out more about [the `raw_json` extensions][raw_json] that made this high level of interoperability possible.\n\nAs a result, migrating from `active_model_serializers` is relatively\nstraightforward because instance methods, inheritance, and mixins work as usual.\n\n### Benchmarks 📊\n\nThis library includes some [benchmarks] to compare performance with similar libraries.\n\nSee [this pull request](https://github.com/ElMassimo/oj_serializers/pull/9) for a quick comparison,\nor check the CI to see the latest results.\n\n### Migrating from other libraries\n\nPlease refer to the [migration guide] for a full discussion of the compatibility\nmodes available to make it easier to migrate from `active_model_serializers` and\nsimilar libraries.\n\n## Formatting 📏\n\nEven though most of the examples above use a single-line style to be succint, I highly recommend writing one attribute per line, sorting them alphabetically (most editors can do it for you), and [always using a trailing comma][trailing_commas].\n\n```ruby\nclass AlbumSerializer \u003c Oj::Serializer\n  attributes(\n    :genres,\n    :name,\n    :release_date,\n  )\nend\n```\n\nIt will make things clearer, minimize the amount of git conflicts, and keep the history a lot cleaner and more meaningful when using `git blame`.\n\n## Special Thanks 🙏\n\nThis library wouldn't be possible without the wonderful and performant [`oj`](https://github.com/ohler55/oj) library. Thanks [Peter](https://github.com/ohler55)! 😃\n\nAlso, thanks to the libraries that inspired this one:\n\n- [`active_model_serializers`][ams]: For the DSL\n- [`panko-serializer`][panko]: For validating that using `Oj::StringWriter` was indeed fast\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felmassimo%2Foj_serializers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felmassimo%2Foj_serializers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felmassimo%2Foj_serializers/lists"}