{"id":15713779,"url":"https://github.com/imdrasil/serializer","last_synced_at":"2025-05-12T23:21:43.511Z","repository":{"id":44930050,"uuid":"203888736","full_name":"imdrasil/serializer","owner":"imdrasil","description":"Simple and fast Crystal object serializer","archived":false,"fork":false,"pushed_at":"2022-01-18T03:06:16.000Z","size":20,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-21T08:14:05.389Z","etag":null,"topics":["crystal-language","json","serialization"],"latest_commit_sha":null,"homepage":null,"language":"Crystal","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/imdrasil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-22T23:33:05.000Z","updated_at":"2023-07-25T14:28:29.000Z","dependencies_parsed_at":"2022-09-03T02:52:01.125Z","dependency_job_id":null,"html_url":"https://github.com/imdrasil/serializer","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imdrasil%2Fserializer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imdrasil%2Fserializer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imdrasil%2Fserializer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imdrasil%2Fserializer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imdrasil","download_url":"https://codeload.github.com/imdrasil/serializer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253838087,"owners_count":21972091,"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":["crystal-language","json","serialization"],"created_at":"2024-10-03T21:33:27.337Z","updated_at":"2025-05-12T23:21:43.484Z","avatar_url":"https://github.com/imdrasil.png","language":"Crystal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Serializer\n\n**Serializer** is a simple JSON serialization library for your object structure. Unlike core `JSON` module's functionality this library only covers serializing objects to JSON without parsing data back. At the same time it provides some free space for maneuvers, precise and flexible configuration WHAT, HOW and WHEN should be rendered.\n\n`Serializer::Base` only ~11% slower than `JSON::Serializable`\n\n```text\n        Serializer 646.00k (  1.55µs) (± 2.52%)  2.77kB/op   1.11× slower\nJSON::Serializable 719.74k (  1.39µs) (± 2.39%)   1.3kB/op        fastest\n```\n\nand at the same time provides next functionality:\n\n* conditional rendering at schema definition stage\n* excluding specific fields at invocation stage\n* separation fields from relations\n* deep relation specification (to be rendered) at invocation stage\n* inheritance\n* optional meta data (can be specified at both definition and invocation stages).\n\n## Installation\n\n1. Add the dependency to your `shard.yml`:\n\n   ```yaml\n   dependencies:\n     serializer:\n       github: imdrasil/serializer\n   ```\n\n2. Run `shards install`\n\n## Usage\n\nLet's assume we have next resources relationship\n\n```crystal\nclass Parent\n  property name, title,\n    children : Array(Child),\n    friends : Array(Child)\n\n  def initialize(@name = \"test\", @title = \"asd\", @children = [] of Child, @friends = [] of Child)\n  end\nend\n\nclass Child\n  property age : Int32, dipper : Child?, address : Address?\n\n  def initialize(@age, @dipper = nil, @address = nil)\n  end\n\n  def some_sub_relation; end\nend\n\nclass Address\n  property street\n\n  def initialize(@street = \"some street\")\n  end\nend\n```\n\nTo be able to serialize data we need to define serializers for each resource:\n\n```crystal\nclass AddressSerializer \u003c Serializer::Base(Address)\n  attributes :street\nend\n\nclass ChildSerializer \u003c Serializer::Base(Child)\n  attribute :age\n\n  has_one :some_sub_relation, ChildSerializer\n  has_one :address, AddressSerializer\n  has_one :dipper, ChildSerializer\nend\n\nclass ModelSerializer \u003c Serializer::Base(Model)\n  attribute :name\n  attribute :title, :Title, if: :test_title\n  attribute :own_field\n\n  has_many :children, ChildSerializer\n  has_many :friends, ChildSerializer\n\n  def test_title(object, options)\n    options.nil? || !options[:test]?\n  end\n\n  def own_field\n    12\n  end\nend\n```\n\n### Attributes\n\nTo specify what should be serialized `attributes` and `attribute` macros are used. `attributes` allows to pass a list of attribute names which maps one-to-one with JSON keys\n\n```crystal\nclass PostSerializer\n  attributes :title, body\nend\n```\n\nAbove serializer will produce next output `{\"title\": \"Some title\", \"body\": \"Post body\"}`. You can precisely configure every field using `attribute` macro. It allows to specify `key` name to be used in JSON and `if` predicate method name to be used to check whether field should be serialized.\n\n```crystal\nclass ModelSerializer \u003c Serializer::Base(Model)\n  attribute :title, :Title, if: :test_title\n\n  def test_title(object, options)\n    options.nil? || !options[:test]?\n  end\nend\n```\n\nAbove serializer will produce next output `{\"Title\": \"Some title\"}` if serializer has got options without `test` set to `true`.\n\nIf serializer has a method with the same name as specified field - it is used.\n\n```crystal\nclass ModelSerializer \u003c Serializer::Base(Model)\n  attribute :name\n\n  def name\n    \"StaticName\"\n  end\nend\n```\n\n### Relations\n\nIf resource has underlying resources to serialize they can be specified with `has_one`, `belongs_to` and `has_many` macro methods that describes relation type between them (one-to-one, one-to-any and one-to-many).\n\n```crystal\nclass ModelSerializer \u003c Serializer::Base(Model)\n  has_many :friends, ChildSerializer\nend\n```\n\nThey also accepts `key` option. There is no `if` support because associations by default isn't rendered.\n\n### Meta\n\nResource meta data can be defined at it's level - overriding `.meta` method.\n\n```crystal\nclass ModelSerializer \u003c Serializer::Base(Model)\n  def self.meta(options)\n    {\n      :page =\u003e options[:page]\n    }\n  end\nend\n```\n\nMethod return value should be `Hash(Symbol, JSON::Any::Type | Int32)`. Also any additional meta attributes may be defined at serialization moment (calling `#serialize` method).\n\n### Inheritance\n\nIf you have complicated domain object relation structure - you can easily present serialization logic using inheritance:\n\n```crystal\nclass ModelSerializer \u003c Serializer::Base(Model)\n  attribute :name\nend\n\nclass InheritedSerializer \u003c ModelSerializer\n  attribute :inherited_field\n\n  def inherited_field\n    1.23\n  end\nend\n```\n\n### Rendering\n\nTo render resource create an instance of required serializer and call `#serialize`:\n\n```crystal\nModelSerializer.new(model).serialize\n```\n\nIt accepts several optional arguments:\n\n* `except` - array of fields that should not be serialized;\n* `includes` - relations that should be included into serialized string;\n* `opts` - options that will be passed to *if* predicate methods and `.meta`;\n* `meta` - meta attributes to be added under `\"meta\"` key at root level; it is merged into default meta attributes returned by `.meta`.\n\n```crystal\nModelSerializer.new(model).serialize(\n  except: [:own_field],\n  includes: {\n    :children =\u003e [:some_sub_relation],\n    :friends =\u003e { :address =\u003e nil, :dipper =\u003e [:some_sub_relation] }\n  },\n  meta: { :page =\u003e 0 }\n)\n```\n\n`includes` should be array or hash (any levels deep) which elements presents relation names to be serialized. `nil` value may be used in hashes as a value to define that nothing additional should be serialized for a relation named by corresponding key.\n\nExample above results in:\n\n```json\n{\n  \"data\":{\n    \"name\":\"test\",\n    \"Title\":\"asd\",\n    \"children\":[],\n    \"friends\":[\n      {\n        \"age\":60,\n        \"address\":{\n          \"street\":\"some street\"\n        },\n        \"dipper\":{\n          \"age\":20,\n          \"some_sub_relation\":null\n        }\n      }\n    ]\n  },\n  \"meta\":{\n    \"page\":0\n  }\n}\n```\n\n\u003e This is pretty JSON version - actual result contains no spaces and newlines.\n\n#### Root key\n\nSerialized JSON root level includes `data` key (and optional `meta` key). It can be renamed to anything by defining `.root_key`\n\n```crystal\nclass ModelSerializer \u003c Serializer::Base(Model)\n  def self.root_key\n    \"model\"\n  end\n\n  attribute :name\nend\n```\n\nFor API details see [documentation](https://imdrasil.github.io/serializer/latest/serializer).\n\n## Contributing\n\n1. Fork it (\u003chttps://github.com/imdrasil/serializer/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## Contributors\n\n- [Roman Kalnytskyi](https://github.com/imdrasil) - creator and maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimdrasil%2Fserializer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimdrasil%2Fserializer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimdrasil%2Fserializer/lists"}