Library / SDK
Yelp/bravado avatar
Yelp/bravado

bravado turns a Swagger 2.0 spec into a live Python client

Bravado is a python client library for Swagger 2.0 services

608 stars118 forksPythonNOASSERTION

At a glance

What is it?
Bravado is Yelp's maintained fork of swagger-py, and instead of generating a client from an OpenAPI 2.0 document it builds the client at runtime from the spec, so the methods you call mirror the service's resources. It ships a synchronous client over requests and an optional asynchronous one over fido, with basic, header and API key authentication configured on the HTTP client rather than the spec.
Who is it for?
bravado fits a Python service that consumes an OpenAPI 2.0 API and wants typed calls without a code generation step in the build, and it does not fit a project whose API is described with OpenAPI 3.x, since the README states the library targets specification version 2.0.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A fork with a narrower target: Swagger 2.0 only

Bravado is a Yelp maintained fork of digium/swagger-py, for use with OpenAPI Specification version 2.0, previously known as Swagger.

The fork lineage matters, because it explains the shape of the library. The original swagger-py was written to consume a Swagger 2.0 document, and Yelp took it over to keep it working rather than replacing it. The README quotes the OpenAPI project to explain the goal: to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection.

And here is the design decision that defines bravado. Client libraries can automatically be generated from the OpenAPI specification, using swagger-codegen, and bravado aims to be a complete replacement for that code generation.

That is a different philosophy from the generated client. A generated client has methods baked into your source tree at build time, which means your API calls break when the spec changes until you regenerate, and your repository carries a directory of machine-written service code. A runtime client reads the spec and builds the interface when the program starts, so the same code keeps working as the service evolves, at the cost of loading and interpreting the spec at startup and of the spec being available at runtime.

The version target is the hard boundary. The library is for OpenAPI 2.0, and a service described with the later OpenAPI 3 document is a different format with different ideas about how requests and responses are modelled, so this library does not cover it.

The client is built from the spec, and the calls read like the API

The usage example is three lines, and it shows the whole model.

python
    from bravado.client import SwaggerClient
    client = SwaggerClient.from_url('http://petstore.swagger.io/v2/swagger.json')
    pet = client.pet.getPetById(petId=1).response().result

The client is created from the URL of a spec, and then the service's resources appear as attributes. In the example, pet is the resource and getPetById is the operation, with the petId parameter passed as a keyword argument, exactly as the specification describes it.

The response object is worth understanding, because the chaining is deliberate. Calling getPetById returns a response wrapper rather than the payload, and you ask that wrapper for the result. The intermediate step is what lets bravado expose the parts of a response a client library often discards, such as the response headers and the status, without inventing a separate API for them.

The point of the design is that the call site is written against the service's own vocabulary. A team that has a Swagger document and a client generated from it will find the two nearly interchangeable at the call site, which means switching between them, or between bravado and hand written requests code, is mostly a matter of the import.

Because the client is built at runtime, the spec is fetched over the network at start of time in this example, which means the location of the spec is configuration your deployment owns, and a network dependency at start up.

Authentication is configured on the HTTP client, not in the spec

Bravado separates the service description from the transport, and the authentication examples all work the same way: you build an HTTP client, configure credentials on it, and hand it to SwaggerClient.

The basic authentication example sets a host and a username and password on a RequestsClient:

python
    from bravado.requests_client import RequestsClient
    from bravado.client import SwaggerClient

    http_client = RequestsClient()
    http_client.set_basic_auth(
        'api.yourhost.com',
        'username', 'password'
    )
    client = SwaggerClient.from_url(
        'http://petstore.swagger.io/v2/swagger.json',
        http_client=http_client,
    )

The header authentication example uses an API key with a parameter name and the location it travels in:

python
    http_client.set_api_key(
        'api.yourhost.com', 'token',
        param_name='api_key', param_in='header'
    )

The param_in argument is the interesting one, since it tells the client whether the key goes in a header or as a query parameter, which is exactly the distinction the specification makes and exactly the detail a hand written client gets wrong when a service supports both.

The third example swaps the transport for an asynchronous one, the Fido client, installed through the fido extra:

python
    from bravado.fido_client import FidoClient
    from bravado.client import SwaggerClient

    http_client = FidoClient()
    client = SwaggerClient.from_url(
        'http://petstore.swagger.io/v2/swagger.json',
        http_client=http_client,
    )

Everything above the transport is identical between the three, which is the payoff of the split. The same spec, the same call sites, and a different concurrency model underneath.

Installation, extras and the dependency list

Installation is a pip command, and there are two flavours.

bash
    $ pip install bravado
bash
    $ pip install bravado[fido]

The first installs the synchronous HTTP client only. The second adds the asynchronous client, so the fido dependency, which is declared in the package metadata as an extra requiring fido 4.2.1 or newer, comes along as well. The comment in the README labels the extras as synchronous and asynchronous clients, RequestsClient and FidoClient.

The runtime dependencies in the package metadata are worth reading, because they tell you what the library does and does not drag in. bravado-core 5.16.1 or newer is the specification handling core, and it is the piece that parses and interprets the OpenAPI document. Then there is msgpack for binary payloads, python-dateutil and pyyaml for the date and YAML handling that specifications require, requests 2.17 or newer for the synchronous transport, six for compatibility helpers, simplejson for the JSON handling, monotonic for a clock that does not go backwards, and typing_extensions for the type annotations.

Two entries in the extras are worth a second look. There is a conditional extra for Python versions below 3.5 that pulls in the typing backport, and there is an integration-tests extra with bottle, ephemeral_port_reserve and pytest, which is what the integration test suite runs against a local server.

The package metadata also declares python_requires of 3.8 or newer, and ships a py.typed marker so that type checkers use the library's own annotations.

Typing, tests and the documentation pipeline

The repository layout shows a library that was modernised in the places that matter for a team using it.

Typing is explicit. There is a mypy.ini at the root, the package ships a py.typed marker in its package data, and typing_extensions is a runtime dependency, so the annotations are part of the distribution rather than an afterthought. For a client whose method names are generated at runtime, that is not a small thing, because it means an editor can still tell you what the call returns.

Testing is handled by tox, with a tox.ini at the root and a Makefile whose default target runs the test suite. There is a .coveragerc, a Coveralls badge in the README and a GitHub Actions build badge, so coverage is measured and reported. The Makefile also has targets for building an egg, developing in place, building the documentation, installing, and cleaning, including a find for stray .pyc and __pycache__ directories.

Documentation is Sphinx based, with a requirements-docs.txt, a docs directory and a readthedocs configuration. The README also points to the hosted documentation at bravado.readthedocs.org, which is where the detailed guides live.

There is a .secrets.baseline file, which is the artefact of a secret scanning tool, and a pre-commit configuration alongside a .pre-commit-config.yaml, plus an AppVeyor configuration and a MANIFEST.in for the source distribution. The CHANGELOG.rst at the root records the history.

The development setup in the README is a virtualenv with tox, and a separate tox environment installs the git pre-commit hooks with tox -e pre-commit install.

The release history looks older than the code, and that is worth checking

Two facts about the state of this project should shape your adoption decision.

The first is the release list. The published releases are v0.7.8, titled as a fix for a UnicodeDecodeError when posting binary files, dated 2015-03-24, then v0.7.4 from 2014-12-16 and v0.7.3 from 2014-12-11. Those tags are more than a decade old, while the last push to the repository was on 2026-04-02 and the repository is not archived. So development continues and the tag feed does not reflect it, which is the classic shape of a project whose releases are cut by hand rather than by automation.

The practical consequence is that you should not assume the version you install matches the source in the repository. The setup.py takes its version from the package's own version module rather than hardcoding it, so the number in the index and the code in git can drift apart, and the release process is documented as being run by Yelp staff following an internal wiki page.

The second is the inconsistency in the Python support metadata. The classifiers list Python 2.7, 3.6 and 3.7, while python_requires declares 3.8 or newer. The classifiers are leftovers from the fork's earlier years, and the requirement field is the one that pip enforces, so a 3.7 environment will be refused even though the classifiers still advertise it.

On the licence, the README states that Bravado is licensed with a BSD 3-Clause License, and the package metadata repeats it as the licence and as the classifier for an OSI approved BSD licence, with the copyright notices for Digium in 2013 and Yelp from 2014 to 2021. The repository records the licence as a custom one that GitHub cannot classify, which is a metadata classification issue rather than a different grant, and the LICENSE.txt file in the tree is the text to read.

Editorial conclusion

bravado fits a Python service that consumes an OpenAPI 2.0 API and wants typed calls without a code generation step in the build, and it does not fit a project whose API is described with OpenAPI 3.x, since the README states the library targets specification version 2.0. Before you depend on it, check the Python version you run, because the package metadata requires 3.8 or newer while the classifier list still mentions 2.7, 3.6 and 3.7, and confirm the release you get from the index, since the published tags in the repository stop in 2015 even though the last push was on 2026-04-02.

Frequently asked questions

What is bravado and who maintains it?

Bravado is a Python client library for Swagger 2.0 services, described as a Yelp maintained fork of digium/swagger-py for use with OpenAPI Specification version 2.0. It aims to be a complete replacement for code generation with swagger-codegen, building the client from the specification at runtime instead of generating source code.

How do I call an API with bravado?

Create a client from the specification URL with SwaggerClient.from_url, then call the resource and operation as attributes, for example client.pet.getPetById(petId=1), and read the payload from .response().result.

How do I add authentication to a bravado client?

Configure it on the HTTP client and pass that client to SwaggerClient.from_url. RequestsClient has set_basic_auth for a host, username and password, and set_api_key for a host and token with a parameter name and param_in, where param_in chooses whether the key is sent as a header or as a query parameter.

Can bravado use an asynchronous HTTP client?

Yes. Install the extra with pip install bravado[fido], then build a FidoClient and pass it to SwaggerClient.from_url as the http_client. The call sites stay the same as with the synchronous RequestsClient.

Which Python versions does bravado support?

The package metadata declares python_requires of 3.8 or newer, and the library ships a py.typed marker with typing_extensions as a dependency. The classifier list is out of date and still mentions Python 2.7, 3.6 and 3.7, but the requirement field is what pip enforces.

Official sources

  1. Issues
  2. README
  3. Releases
  4. Yelp/bravado on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/yelp-bravado.svg)](https://hysenlabs.com/projects/yelp-bravado)

Was this useful?