{"id":16549806,"url":"https://github.com/uiur/keema-resource","last_synced_at":"2026-05-07T22:36:06.653Z","repository":{"id":59973301,"uuid":"540379156","full_name":"uiur/keema-resource","owner":"uiur","description":"A JSON object presenter with the ability of generating JSON Schema / OpenAPI Schema","archived":false,"fork":false,"pushed_at":"2022-11-10T13:55:48.000Z","size":54,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-04T15:27:55.666Z","etag":null,"topics":["api","json-schema","ruby"],"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/uiur.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-09-23T09:59:30.000Z","updated_at":"2023-06-19T02:44:39.000Z","dependencies_parsed_at":"2023-01-21T14:31:31.316Z","dependency_job_id":null,"html_url":"https://github.com/uiur/keema-resource","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/uiur/keema-resource","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uiur%2Fkeema-resource","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uiur%2Fkeema-resource/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uiur%2Fkeema-resource/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uiur%2Fkeema-resource/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uiur","download_url":"https://codeload.github.com/uiur/keema-resource/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uiur%2Fkeema-resource/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32759440,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-07T02:14:30.463Z","status":"ssl_error","status_checked_at":"2026-05-07T02:14:29.405Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["api","json-schema","ruby"],"created_at":"2024-10-11T19:31:31.650Z","updated_at":"2026-05-07T22:36:06.627Z","avatar_url":"https://github.com/uiur.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# keema-resource ![test](https://github.com/uiur/keema-resource/actions/workflows/main.yml/badge.svg)\n\nkeema-resource is a JSON object presenter with the power of generating JSON Schema / OpenAPI 3.0 Schema.\nIt provides minimalistic-style DSL to describe JSON Schema.\n\nIt's intended to be used as an alternative to active_model_serializers or jbuilder.\n\n## Overview\n\n```ruby\nclass ProductResource \u003c Keema::Resource\n  field :id, Integer\n  field :name, String\n  field :price, Float\n  field :status, enum(:published, :unpublished)\n  field :description, String, null: true\n  field :image_url, String, optional: true\n\n  field :out_of_stock, Bool\n  field :tags, [String]\n\n  field :created_at, Time\nend\n\n# Serialize object to json representation\nproduct = Product.new(\n  id: 1,\n  name: \"foo\",\n  status: 'published',\n  price: 12.3,\n  description: nil,\n  out_of_stock: false,\n  tags: ['food', 'sushi'],\n  image_url: 'foo.png',\n  created_at: Time.now\n)\nProductResource.serialize(product)\n#=\u003e\n# {\n#   id: 1,\n#   name: \"foo\",\n#   price: 12.3,\n#   status: \"published\",\n#   description: nil,\n#   out_of_stock: false,\n#   tags: [\"food\", \"sushi\"],\n#   created_at: \"2022-11-04T09:49:30.297+09:00\"\n# }\n\n# Generate json schema\nProductResource.to_json_schema\n\n# Generate openapi-compatible json schema\nProductResource.to_openapi\n```\n\n## JSON serialization\n`.serialize` method serializes an object to a JSON serializable hash.\nIt acts as an object presenter.\n\nFor example:\n\n```ruby\nclass ProductResource \u003c Keema::Resource\n  field :id, Integer\n  field :name, String\n  field :price, Float\nend\n\n# `serialize` method takes an object.\nProductResource.serialize(product)\n#=\u003e\n# {\n#   id: 1,\n#   name: \"foo\",\n#   price: 10.0\n# }\n\n# Also, it can take an array of objects. It returns output as an array.\nProductResource.serialize(products)\n#=\u003e\n# [\n#   {\n#     id: 1,\n#     name: 'foo',\n#     price: 10.0\n#   },\n#   {\n#     id: 2,\n#     name: 'bar',\n#     price: 20.0\n#   }\n# ]\n```\n\nIn Rails, you can use the resource in action like this:\n\n```ruby\ndef index\n  products = Product.order(:id).limit(20)\n  render json: ProductResource.serialize(products)\nend\n```\n\n### Selecting fields\nBy default, `serialize` renders all of not-optional fields.\n\n```ruby\nclass ProductResource \u003c Keema::Resource\n  field :id, Integer  # default is optional: false\n  field :name, String\n  field :price, Float\n  field :description, String, optional: true\nend\nProductResource.serialize(products)\n#=\u003e\n# [\n#   {\n#     id: 1,\n#     name: \"foo\",\n#     price: 10.0\n#   }\n# ]\n```\n\nTo include optional fields, you need to specify them in fields option explicitly:\n\n```ruby\nProductResource.serialize(products, fields: [\n  :*, # `*` means all of not-optional fields\n  :description\n])\n#=\u003e\n# [\n#   {\n#     id: 1,\n#     name: \"foo\",\n#     price: 10.0,\n#     description: 'long product description'\n#   }\n# ]\n```\n\nIn some cases, you may want to render only partial fields because of performance reason etc.\n\n```ruby\nProductResource.serialize(products, fields: [\n  :id,\n  :name,\n])\n#=\u003e\n# [\n#   {\n#     id: 1,\n#     name: 'foo',\n#   },\n#   {\n#     id: 2,\n#     name: 'bar',\n#   }\n# ]\n```\n\n### Nested resource\nIt can render nested objects by specifying another resource in field type.\n\nFor example, when an object has has-many associations,\n\n```ruby\nclass ProductResource \u003c Keema::Resource\n  field :id, Integer\n  field :name, String\n  field :product_images, [ProductImageResource]  # `[A]` means Array of A\nend\n\nclass ProductImageResource \u003c Keema::Resource\n  field :id, Integer\n  field :url, String\nend\n\nProductResource.serialize(products)\n#=\u003e\n# {\n#   id: 1,\n#   name: 'foo',\n#   product_images: [\n#     { id: 1, url: 'foo.png' },\n#     { id: 2, url: 'bar.png' },\n#   ]\n# }\n```\n\nAlso, it can select partial fields of nested resource.\n\n```ruby\nProductResource.serialize(products, fields: [\n  :id,\n  :name,\n  product_images: [:id]  # nested fields can be specified with hash form\n])\n```\n\n### Adding methods\nYou can add methods in resource class and override the behavior of the original object.\n\n```ruby\nrequire 'securerandom'\nclass ProductResource \u003c Keema::Resource\n  field :id, String\n  field :hex, String\n\n  def id\n    # object is the original object (`product` in here)\n    \"product-#{object.id}\"\n  end\n\n  def hex\n    SecureRandom.hex\n  end\nend\n\nProduct = Struct.new(:id, keyword_init: true)\nproduct = Product.new(id: 1234)\n\nProductResource.serialize(product)\n#=\u003e {:id=\u003e\"product-1234\", :hex=\u003e\"71ab70d16b5b0801357a6c088abdbac2\"}\n```\n\n### Lazy evaluation\nOnly selected fields are rendered. It doesn't evaluate unnecessary fields.\n\nIt helps to avoid performance problems such as N+1.\n\nFor example:\n\n```ruby\nclass ProductResource \u003c Keema::Resource\n  field :id, String\n  field :fast, String\n  field :slow, String\n\n  def fast\n    'fast'\n  end\n\n  def slow\n    sleep 10 \u0026\u0026 'slow'\n  end\nend\n\nProduct = Struct.new(:id, keyword_init: true)\nproduct = Product.new(id: 1234)\n\nProductResource.serialize(product, fields: [\n  :id, :fast\n])\n#=\u003e {:id=\u003e1234, :fast=\u003e\"fast\"}\n# It returns data with no problem.\n# Only selected fields are rendered. The slow field is not evaluated.\n```\n\n### Using context\nIn some cases, you may need to use context other than an object. (e.g. current_user etc.)\n\n`serialize` method can take context hash as an option. Context can be accessed from methods.\n\n\n```ruby\nclass PostResource \u003c Keema::Resource\n  field :id, Integer\n  field :title, String\n  field :editable, Bool\n\n  def editable\n    context[:current_user].post_ids.include?(object.id)\n  end\nend\n\nUser = Struct.new(:post_ids, keyword_init: true)\nPost = Struct.new(:id, :title, keyword_init: true)\n\ncurrent_user = User.new(post_ids: [1])\npost = Post.new(id: 1, title: 'foo')\n\nPostResource.serialize(post, context: {\n  current_user: current_user\n})\n#=\u003e {:id=\u003e1, :title=\u003e\"foo\", :editable=\u003etrue}\n```\n\nAlso, context hash is passed into nested resources.\n\n```ruby\nclass UserResource \u003c Keema::Resource\n  field :id, Integer\n  field :posts, [PostResource]\nend\n\nuser = OpenStruct.new(id: 2, posts: [post])\nUserResource.serialize(user, context: {\n  current_user: current_user\n})\n#=\u003e {:id=\u003e2, :posts=\u003e[{:id=\u003e1, :title=\u003e\"foo\", :editable=\u003etrue}]}\n```\n\n## Schema generation\nIt can generate JSON Schema and OpenAPI schema with `.to_openapi` and `.to_json_schema`.\n\n```ruby\nclass ProductResource \u003c Keema::Resource\n  field :id, Integer\n  field :name, String\n  field :price, Float\n  field :created_at, Time\nend\n\nProductResource.to_openapi\n#=\u003e\n# {\n#   title: 'ProductResource',\n#   type: :object,\n#   properties: {\n#     id: { type: :integer },\n#     name: { type: :string },\n#     price: { type: :number },\n#     created_at: { type: :string, format: :'date-time' }\n#   },\n#   additionalProperties: false,\n#   required: [\n#     :id,\n#     :name,\n#     :price,\n#     :created_at,\n#   ]\n# }\n```\n\n### Selecting schema fields\n`.select(fields)` method creates a subset of a resource. Selected fields are specified as required.\n\n```ruby\nProductResource.select([:id, :name]).to_openapi\n#=\u003e\n# {\n#   type: :object,\n#   properties: {\n#     id: { type: :integer },\n#     name: { type: :string },\n#   },\n#   additionalProperties: false,\n#   required: [\n#     :id,\n#     :name\n#   ]\n# }\n```\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'keema-resource', github: 'uiur/keema-resource'\n```\n\nAnd then execute:\n\n    $ bundle install\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/uiur/keema-resource. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/uiur/keema-resource/blob/main/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the Keema::Resource project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/uiur/keema-resource/blob/main/CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuiur%2Fkeema-resource","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuiur%2Fkeema-resource","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuiur%2Fkeema-resource/lists"}