{"id":28550806,"url":"https://github.com/dropbox/babelapi","last_synced_at":"2025-06-27T23:33:29.479Z","repository":{"id":18868724,"uuid":"22085645","full_name":"dropbox/babelapi","owner":"dropbox","description":"Define an API once in Babel. Implement or use an existing code generator to map the API definition into usable objects and functions in any programming language.","archived":false,"fork":false,"pushed_at":"2016-11-05T18:04:55.000Z","size":1039,"stargazers_count":4,"open_issues_count":1,"forks_count":7,"subscribers_count":27,"default_branch":"master","last_synced_at":"2025-06-10T03:11:21.629Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dropbox.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-07-22T00:55:00.000Z","updated_at":"2022-09-13T16:28:20.000Z","dependencies_parsed_at":"2022-07-14T01:10:40.847Z","dependency_job_id":null,"html_url":"https://github.com/dropbox/babelapi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dropbox/babelapi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2Fbabelapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2Fbabelapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2Fbabelapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2Fbabelapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dropbox","download_url":"https://codeload.github.com/dropbox/babelapi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dropbox%2Fbabelapi/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262351854,"owners_count":23297636,"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":[],"created_at":"2025-06-10T03:10:22.428Z","updated_at":"2025-06-27T23:33:29.471Z","avatar_url":"https://github.com/dropbox.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"*****\nBabel\n*****\n\n**This repository is a stub. No code is available yet. Check back soon.**\n\nDefine an API once in Babel. Use code generators to translate your\nspecification into objects and functions in the programming languages of your\nchoice.\n\nBabel is made up of several components:\n\n    1. An interface-description language (IDL) for specifying APIs.\n    2. A command-line tool (``babelapi``) that takes an API specification and\n       generator module, and generates output.\n    3. A Python-interface for defining new generators.\n    4. A JSON-compatible serialization format.\n\nBabel is in active use for the `Dropbox v2 API\n\u003chttp://www.dropbox.com/developers\u003e`_. Right now, the only available generator\nis for Python, but we're working on releasing the other ones we have\ninternally: Swift, C#, Java, Go, JavaScript, and HTML documentation.\n\n    * Introduction\n        * Motivation_\n        * Installation_\n        * `Taste of Babel \u003c#a-taste-of-babel\u003e`_\n    * `Language Reference (.babel) \u003cdoc/lang_ref.rst\u003e`_\n        * `Choosing a Filename \u003cdoc/lang_ref.rst#choosing-a-filename\u003e`_\n        * `Comments \u003cdoc/lang_ref.rst#comments\u003e`_\n        * `Namespace \u003cdoc/lang_ref.rst#ns\u003e`_\n        * `Primitive Types \u003cdoc/lang_ref.rst#primitive-types\u003e`_\n        * `Alias \u003cdoc/lang_ref.rst#alias\u003e`_\n        * `Struct \u003cdoc/lang_ref.rst#struct\u003e`_\n        * `Union \u003cdoc/lang_ref.rst#union\u003e`_\n        * `Nullable Type \u003cdoc/lang_ref.rst#nullable-type\u003e`_\n        * `Route \u003cdoc/lang_ref.rst#route\u003e`_\n        * `Include \u003cdoc/lang_ref.rst#include\u003e`_\n        * `Documentation \u003cdoc/lang_ref.rst#doc\u003e`_\n        * `Formal Grammar \u003cdoc/lang_ref.rst#formal-grammar\u003e`_\n    * `Using Generated Code \u003cdoc/using_generator.rst\u003e`_\n        * `Compile with the CLI \u003cdoc/using_generator.rst#compile-with-the-cli\u003e`_\n        * `Python Guide \u003cdoc/using_generator.rst#python-guide\u003e`_\n    * `Managing Specs \u003cdoc/managing_specs.rst\u003e`_\n        * `Using Namespaces \u003cdoc/managing_specs.rst#using-namespaces\u003e`_\n        * `Splitting a Namespace Across Files \u003cdoc/managing_specs.rst#splitting-a-namespace-across-files\u003e`_\n        * `Using Header Files \u003cdoc/managing_specs.rst#using-header-files\u003e`_\n        * `Separating Public and Private Routes \u003cdoc/managing_specs.rst#separation-public-and-private-routes\u003e`_\n    * `Evolving a Spec \u003cdoc/evolve_spec.rst\u003e`_\n        * `Background \u003cdoc/evolve_spec.rst#background\u003e`_\n        * `Sender-Recipient \u003cdoc/evolve_spec.rst#sender-recipient\u003e`_\n        * `Backwards Incompatible Changes \u003cdoc/evolve_spec.rst#backwards-incompatible-changes\u003e`_\n        * `Backwards Compatible Changes \u003cdoc/evolve_spec.rst#backwards-compatible-changes\u003e`_\n        * `Planning for Backwards Compatibility \u003cdoc/evolve_spec.rst#planning-for-backwards-compatibility\u003e`_\n        * `Leader-Clients \u003cdoc/evolve_spec.rst#leader-clients\u003e`_\n        * `Route Versioning \u003cdoc/evolve_spec.rst#route-versioning\u003e`_\n    * `Writing a Generator (.babelg.py) \u003cdoc/generator_ref.rst\u003e`_\n        * `Using the API Object \u003cdoc/generator_ref.rst#using-the-api-object\u003e`_\n        * `Creating an Output File \u003cdoc/generator_ref.rst#creating-an-output-file\u003e`_\n        * `Emit Methods \u003cdoc/generator_ref.rst#emit-methods\u003e`_\n        * `Indentation \u003cdoc/generator_ref.rst#indentation\u003e`_\n        * `Examples \u003cdoc/generator_ref.rst#examples\u003e`_\n    * `JSON Serializer \u003cdoc/json_serializer.rst\u003e`_\n    * `Network Protocol \u003cdoc/network_protocol.rst\u003e`_\n\n.. _motivation:\n\nMotivation\n==========\n\nBabel was birthed at Dropbox at a time when it was becoming clear that API\ndevelopment needed to be scaled beyond a single team. The company was\nundergoing a large expansion in the number of product groups, and it wasn't\nscalable for the API team, which traditionally dealt with core file operations,\nto learn the intricacies of each product and build their APIs.\n\nBabel's chief goal is to decentralize API development and ownership at Dropbox.\nTo be successful, it needed to do several things:\n\n**Decouple APIs from SDKS**: Dropbox has first-party clients for our mobile\napps, desktop client, and website. Each of these is implemented in a different\nlanguage. And we want to make onboarding easier for third-parties by providing\nthem with SDKs. It's untenable to ask product groups that build APIs to also\nimplement these endpoints in a half-dozen different language-specific SDKs.\nWithout decoupling, as was the case in our v1 API, the SDKs will inevitably\nfall behind. Our solution is to have our SDKs automatically generated.\n\n**Improve Visibility into our APIs**: These days, APIs aren't just in the\ndomain of engineering. Product managers, product specialists, partnerships,\nsales, and services groups all need to have clear and accurate specifications\nof our APIs. After all, APIs define Dropbox's data models and functionlaity.\nBefore Babel, API design documents obseleted by changes during implementation\nwere the source of truth.\n\n**Consistency and Predictability**: Consistency ranging from documentation\ntense to API patterns are important for making an API predictable and therefore\neasier to use. We needed an easy way to make and enforce patterns.\n\n**JSON**: To make consumption easier for third parties, we wanted our data\ntypes to map to JSON. For cases where serialization efficiency\n(space and time) are important, you can try using msgpack (alpha support\navailable in the Python generator). It's possible also to define your own\nserialization scheme, but at that point, you may consider using something like\n`Protobuf \u003chttps://github.com/google/protobuf\u003e`_.\n\nAssumptions\n-----------\n\nBabel makes no assumptions about the transport layer being used to make API\nrequests and return responses; its first use case is the Dropbox v2 API which\noperates over HTTP. Babel does not come with nor enforce any particular RPC\nframework.\n\nBabel makes some assumptions about the data types supported in target\nprogramming languages. It's assumed that there is a capacity for representing\ndictionaries (unordered string keys -\u003e value), lists, numeric types, and\nstrings.\n\n\nBabel assumes that a route (or API endpoint) can have its argument and\nresult types defined without relation to each other. In other words, the\ntype of response does not change based on the input to the endpoint. An\nexception to this rule is afforded for error responses.\n\n.. _installation:\n\nInstallation\n============\n\nDownload or clone BabelAPI, and run the following in its root directory::\n\n    $ sudo python setup.py install\n\nThis will install a script ``babelapi`` to your PATH that can be run from the\ncommand line::\n\n    $ babelapi -h\n\nAlternative\n-----------\n\nIf you choose not to install ``babelapi`` using the method above, you will need\nto ensure that you have the Python packages ``ply`` and ``six``, which can be\ninstalled through ``pip``::\n\n    $ pip install ply\u003e=3.4 six\u003e=1.3.0\n\nIf the ``babelapi`` package is in your PYTHONPATH, you can replace ``babelapi``\nwith ``python -m babelapi.cli`` as follows::\n\n    $ python -m babelapi.cli -h\n\nIf you have the ``babelapi`` package on your machine, but did not install it or\nadd its location to your PYTHONPATH, you can use the following::\n\n    $ PYTOHNPATH=path/to/babelapi python -m babelapi.cli -h\n\n.. taste-of-babel:\n\nA Taste of Babel\n================\n\nHere we define a hypothetical route that shows up in some form or another in\nAPIs for web services: querying the account information for a user of a\nservice. Our hypothetical spec lives in a file called ``users.babel``::\n\n    # We put this in the \"users\" namespace in anticipation that\n    # there would be many user-account-related routes.\n    namespace users\n\n    route get_account (GetAccountReq, Account, GetAccountErr)\n        \"Get information about a specified user's account.\"\n\n    # This struct represents the input data to the route.\n    struct GetAccountReq\n        account_id AccountId\n\n    # We define an AccountId as being a 10-character string\n    # once here to avoid declaring it each time.\n    alias AccountId = String(min_length=10, max_length=10)\n\n    struct Account\n        \"Information about a user's account.\"\n\n        account_id AccountId\n            \"A unique identifier for the user's account.\"\n        email String(pattern=\"^[^@]+@[^@]+\\.[^@]+$\")\n            \"The e-mail address of the user.\"\n        name String(min_length=1)?\n            \"The user's full name. :val:`null` if no name was provided.\"\n        status Status\n            \"The status of the account.\"\n\n        example default \"A regular user\"\n            account_id=\"id-48sa2f0\"\n            email=\"alex@example.org\"\n            name=\"Alexander the Great\"\n            status=active\n\n    union Status\n        active\n            \"The account is active.\"\n        inactive Timestamp(\"%a, %d %b %Y %H:%M:%S\")\n            \"The account is inactive. The value is when the account was\n            deactivated.\"\n\n    # This union represents the possible errors that might be returned.\n    union GetAccountErr\n        no_account\n            \"No account with the requested id could be found.\"\n        perm_denied\n            \"Insufficient privileges to query account information.\"\n        unknown*\n\nUsing the Python generator, we can generate a Python module that mirrors this\nspecification using the command-line interface. From the top-level of the\n``babelapi`` folder, try::\n\n    $ babelapi generator/python/python.babelg.py . users.babel\n\nNow we can interact with the specification in Python::\n\n    $ python -i users.py\n    \u003e\u003e\u003e a = Account()\n    \u003e\u003e\u003e a.account_id = 1234 # fails type validation\n    Traceback (most recent call last):\n      ...\n    babel_data_types.ValidationError: '1234' expected to be a string, got integer\n\n    \u003e\u003e\u003e a.account_id = '1234' # fails length validation\n    Traceback (most recent call last):\n      ...\n    babel_data_types.ValidationError: '1234' must be at least 10 characters, got 4\n\n    \u003e\u003e\u003e a.account_id = 'id-48sa2f0' # passes validation\n\n    \u003e\u003e\u003e # Now we use the included JSON serializer\n    \u003e\u003e\u003e from babel_serializers import json_encode\n    \u003e\u003e\u003e a2 = Account(account_id='id-48sa2f0', name='Alexander the Great',\n    ...              email='alex@example.org', status=Status.active)\n    \u003e\u003e\u003e json_encode(GetAccountRoute.result_data_type, a2)\n    '{\"status\": \"active\", \"account_id\": \"id-48sa2f0\", \"name\": \"Alexander the Great\", \"email\": \"alex@example.org\"}'\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdropbox%2Fbabelapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdropbox%2Fbabelapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdropbox%2Fbabelapi/lists"}