{"id":25436710,"url":"https://github.com/getbannerman/babl","last_synced_at":"2025-11-01T04:30:22.727Z","repository":{"id":62553902,"uuid":"91356083","full_name":"getbannerman/babl","owner":"getbannerman","description":"JSON templating on steroids","archived":false,"fork":false,"pushed_at":"2020-07-23T10:24:31.000Z","size":355,"stargazers_count":29,"open_issues_count":0,"forks_count":1,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-01-16T00:39:35.569Z","etag":null,"topics":["api","babl","babl-template","dependency-analysis","dsl","functional","immutable","json","json-schema","preloader","rails","ruby","template-engine"],"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/getbannerman.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2017-05-15T15:49:28.000Z","updated_at":"2024-02-09T13:32:54.000Z","dependencies_parsed_at":"2022-11-03T05:00:18.941Z","dependency_job_id":null,"html_url":"https://github.com/getbannerman/babl","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getbannerman%2Fbabl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getbannerman%2Fbabl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getbannerman%2Fbabl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getbannerman%2Fbabl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getbannerman","download_url":"https://codeload.github.com/getbannerman/babl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239132704,"owners_count":19587107,"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":["api","babl","babl-template","dependency-analysis","dsl","functional","immutable","json","json-schema","preloader","rails","ruby","template-engine"],"created_at":"2025-02-17T08:21:51.350Z","updated_at":"2025-11-01T04:30:22.688Z","avatar_url":"https://github.com/getbannerman.png","language":"Ruby","readme":"![BABL Logo](https://github.com/getbannerman/babl/raw/master/logo-babl.png)\n\n[![Build Status](https://travis-ci.org/getbannerman/babl.svg?branch=master)](https://travis-ci.org/getbannerman/babl)\n[![Coverage Status](https://coveralls.io/repos/github/getbannerman/babl/badge.svg)](https://coveralls.io/github/getbannerman/babl)\n[![Gem](https://img.shields.io/gem/v/babl-json.svg)](https://rubygems.org/gems/babl-json)\n[![Downloads](https://img.shields.io/gem/dt/babl-json.svg)](https://rubygems.org/gems/babl-json)\n\nBABL (Bannerman API Builder Language) is a functional Ruby DSL for generating JSON in APIs.\n\nIt plays a role similar to [RABL](https://github.com/nesquena/rabl), [JBuilder](https://github.com/rails/jbuilder), [Grape Entity](https://github.com/ruby-grape/grape-entity), [AMS](https://github.com/rails-api/active_model_serializers), and many others.\n\n# Example\n\n```\ngem install babl-json\n```\n\n```ruby\nrequire 'babl'\nrequire 'date'\n\nAuthor = Struct.new(:name, :birthyear)\nArticle = Struct.new(:author, :title, :body, :date, :comments)\nComment = Struct.new(:author, :date, :body)\n\n# Let's define some data\ndata = [\n    Article.new(\n        Author.new(\"Fred\", 1990),\n        'Introducing BABL',\n        'Blablabla',\n        DateTime.now,\n        [\n            Comment.new(\n                Author.new(\"Luke\", 1991),\n                DateTime.now,\n                'Great gem'\n            )\n        ]\n    )\n]\n\n# Define a template\ntemplate = Babl.source {\n\n    # A template can be stored in a variable (\"inline partial\") and re-used later.\n    # For instance, this one serializes an Author.\n    author = object(\n        name: _,\n        birthyear: _\n    )\n\n    # Produce a JSON object\n    object(\n\n        # Visit each article of from collection and produce a JSON object for each elements\n        articles: each.object(\n\n            # nav(:iso8601) can also be seen as a method call.\n            # The method #iso8601 will be called on the date during rendering.\n            date: _.nav(:iso8601),\n\n            # '_' is a shortcut for 'nav(:title)' and 'nav(:body)'\n            title: _,\n            body: _,\n\n            # You can chain another template using call()\n            author: _.call(author),\n\n            # Visit each comment, and produce a JSON object for each of them.\n            comments: _.each.object(\n\n                # In Ruby, .() is just a syntax sugar for .call()\n                author: _.(author),\n\n                # Type assertions can be (optionally) specified.\n                # - They add runtime type checks\n                # - They are added to JSON-Schema\n                body: _.string,\n                date: _.nav(:iso8601).string\n            )\n        )\n    )\n}\n\n# All the magic happens here: the template is transformed into a fast serializer.\ncompiled_template = template.compile\n\n# Serialize some data into JSON\ncompiled_template.json(data)\n\n# =\u003e\n# {\n#     \"articles\":[\n#       {\n#         \"date\":\"2017-09-07T08:42:42+02:00\",\n#         \"title\":\"Introducing BABL\",\n#         \"body\":\"Blablabla\",\n#         \"author\":{\n#           \"name\":\"Fred\",\n#           \"birthyear\":1990\n#         },\n#         \"comments\":[\n#           {\n#             \"author\":{\n#               \"name\":\"Luke\",\n#               \"birthyear\":1991\n#             },\n#             \"body\":\"Great gem\",\n#             \"date\":\"2017-09-07T08:42:42+02:00\"\n#           }\n#         ]\n#       }\n#     ]\n#   }\n\n# render() is like json(), but produces a Hash instead of a JSON\ncompiled_template.render(data)\n\n# Output a JSON-Schema description of the template\ncompiled_template.json_schema\n```\n\n# Benchmark\n\n```\n                                     user     system      total        real\nRABL                             3.180000   0.010000   3.190000 (  3.189780)\nJBuilder                         0.700000   0.000000   0.700000 (  0.708928)\nBABL                             0.540000   0.000000   0.540000 (  0.540724)\nBABL (compiled once)             0.410000   0.010000   0.420000 (  0.412431)\nHandwritten Ruby                 0.080000   0.000000   0.080000 (  0.081407)\n```\n\nResults using [code generation [WIP]](https://github.com/getbannerman/babl/pull/21):\n```\n                                     user     system      total        real\nBABL (compiled once + codegen)   0.170000   0.000000   0.170000 (  0.168479)\n```\nSee [source code](spec/perfs/comparison_spec.rb).\n\n# Features\n\n## Template compilation\n\nA BABL template has to be compiled before it can be used. This approach carries several advantages:\n- Many errors can be detected earlier during the development process.\n- Partials are resolved only once, during compilation: zero overhead at render time.\n- Template fragments which are provably constant are pre-rendered at compilation time.\n- [Code generation [WIP]](https://github.com/getbannerman/babl/pull/21) should bring performances close to handcrafted Ruby code.\n\n## Automatic documentation (JSON schema)\n\nBABL can automatically document a template by generating a JSON-Schema. Combined with optional [type-checking assertions](pages/operators.md#typed), it becomes possible to do some exciting things.\n\nFor instance, it is possible to generate TypeScript interfaces by feeding the exported JSON-Schema to https://github.com/bcherny/json-schema-to-typescript.\n\nSee [how to generate a JSON-Schema](pages/templates.md#json_schema).\n\n## Dependency analysis (automatic preloading)\n\nDue to the static nature of BABL templates, it is possible to determine in advance which methods will be called on models objects during rendering. This is called dependency analysis. In practice, the extracted dependencies can be passed to a preloader, in order to avoid all N+1 issues.\n\nPlease note that this requires a compatible preloader implementation. At Bannerman, we are using **Preeloo**. It natively supports ActiveRecord associations, computed columns, and custom preloadable properties. Unfortunately, it hasn't been released publicly (yet), because it still has bugs and limitations.\n\n# Resources\n\n- [Understanding BABL: fundamental concepts](pages/concepts.md)\n- [Getting started (with Rails)](pages/getting_started.md)\n- [Playing with templates (without Rails)](pages/templates.md)\n- [List of all operators](pages/operators.md)\n- [Limitations](pages/limitations.md)\n- [Design rationale](pages/rationale.md)\n- [Changelog](CHANGELOG.md)\n\n# License\n\nCopyright (c) 2017 [Bannerman](https://www.bannerman.com/), [Frederic Terrazzoni](https://github.com/fterrazzoni)\n\nLicensed under 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%2Fgetbannerman%2Fbabl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetbannerman%2Fbabl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetbannerman%2Fbabl/lists"}