# Connexion: spec-first Python APIs driven by an OpenAPI file

> Connexion is an Apache-2.0 Python framework that reads your OpenAPI or Swagger specification and wires the routes, validation and serialization for you. It fits teams that want the spec to be the contract, not a byproduct of the code.

**spec-first/connexion** — Connexion is a modern Python web framework that makes spec-first and api-first development easy.

- Repository: https://github.com/spec-first/connexion
- Website: https://connexion.readthedocs.io/en/latest/
- Stars: 4,614 · Forks: 787
- Language: Python
- License: Apache-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/spec-first-connexion

## The problem Connexion solves: the spec stops drifting from the code

Most Python web frameworks generate documentation after the fact. You decorate a function with a route, write a docstring or attach a schema, and a tool later emits an OpenAPI file. The README argues that this ordering produces specifications that "often end up lacking details" and mix documentation with implementation logic. Connexion inverts it. You write the OpenAPI or Swagger specification first, and the framework reads it to decide which URLs exist, which parameters are legal, what a valid body looks like, and how a return value should be serialized.

The audience is narrow and identifiable. It is teams where more than one group depends on the same HTTP interface: a backend team and a mobile team, or several microservices with a shared contract. If the specification is the artifact you review and version, Connexion treats it as executable rather than decorative. If you are the only consumer of your own API, the extra YAML is overhead you will feel at every endpoint you add.

## How the specification becomes routes: operationId as the link

The mechanism is a lookup. Each operation in the specification carries an operationId, and that string names the Python function Connexion should call. The README's example uses run.post_greeting for a POST on /greeting/{name}, which means the function lives in a module named run and is named post_greeting. There are no @route decorators. Registration happens when you call app.add_api("openapi.yaml"), and the paths in that file become the application's paths.

Parameters are unpacked into the function signature by name, so a handler declares name: str and greeting: str and receives them without touching a request object. Return values are serialized according to the response schema, which is why the handler can return a plain string and a status code. Headers, query parameters and bodies are validated against the specification before your function runs. Authentication is handled at the same layer, which keeps credential checks out of the handler body. The repository ships examples for apikey, basicauth, jwt, oauth2 and oauth2_local_tokeninfo, so those schemes are demonstrated rather than merely mentioned.

## Three ways to mount Connexion: AsyncApp, FlaskApp, ConnexionMiddleware

Connexion 3 does not force a single application object. The AsyncApp is described as a lightweight application with native asynchronous support, and the README recommends it for new projects with no reason to choose otherwise. The FlaskApp exists for two stated reasons: migrating from Connexion 2.x, and reaching into the Flask ecosystem. That second reason is the honest one. If you depend on Flask extensions, FlaskApp is the only path that keeps them working.

The third option wraps something you already have. ConnexionMiddleware can be placed around any ASGI or WSGI application, so an existing service written in another framework can gain Connexion's validation and routing without a rewrite. The README's snippet imports an App from a module it calls asgi_framework and wraps it.

This is a real architectural choice rather than a cosmetic one. AsyncApp and ConnexionMiddleware sit in ASGI territory, while FlaskApp inherits WSGI semantics and the Flask request lifecycle. The framework's own guidance is to pick AsyncApp unless you have a specific reason, and the two specific reasons it names are migration and Flask compatibility.

## Installing Connexion and running a first endpoint

The package installs from PyPI. The README gives a single command, and the extras are separate because they pull optional dependencies.

```bash
pip install connexion
```

Three extras are documented. swagger-ui enables the Swagger UI console with live documentation and a try-it-out feature. uvicorn enables app.run() for development instead of requiring an external ASGI server. flask enables the FlaskApp. They combine in one bracket list.

```bash
pip install connexion[swagger-ui,uvicorn]
```

With that installed, a minimal application is three lines. The name passed to the constructor is the module name, following the pattern used by the framework examples.

```python
from connexion import AsyncApp

app = AsyncApp(__name__)
```

The specification and the handler are two files. The handler declares the parameters it expects and returns a tuple of body and status.

```python
def post_greeting(name: str, greeting: str):
    return f"{greeting} {name}", 200
```

The specification names that function through operationId and declares the response media type.

```yaml
paths:
  /greeting/{name}:
    post:
      operationId: run.post_greeting
      responses:
        '200':
          content:
            text/plain:
              schema:
                type: string
```

Registering the API is the step that binds the two files together. After this call, a POST to /greeting/ with a name in the path reaches the handler, and the return value is serialized as text/plain.

```python
app.add_api("openapi.yaml")
```

The repository also provides a command line interface for working against a specification before the implementation exists: connexion run openapi.yaml. The README describes it as a way to test and mock your specification, which is useful when the spec is written first and the handlers are not.

## Where Connexion gets in the way

The spec-first ordering is the limitation as much as the feature. Every endpoint you add begins in YAML, and the operationId string is the only connection between that file and your code. Rename a function or move it to another module and the link breaks at registration time. There is no decorator to keep the two in sync, and the README does not document any tooling that rewrites operationId values for you.

The framework's own comparison concedes the trade-off from the other side. Generating a specification from code is described as producing thin documentation, but that approach never blocks a developer who wants to ship an endpoint before writing the contract. With Connexion, the contract is the entry point. If your team treats OpenAPI as a checkbox artifact produced at release time, the workflow will feel like ceremony rather than validation.

The middleware option carries its own cost. Wrapping an existing ASGI or WSGI application gives you Connexion's validation layer, but the specification still has to describe routes that application already implements. The README does not describe how much of an existing application's routing Connexion takes over in that configuration, so the boundary between the wrapped app and the middleware is something to establish by reading the documentation rather than assuming.

## Connexion against code-first frameworks like FastAPI

The closest comparison is a code-first framework that derives an OpenAPI document from type hints and decorators. FastAPI is the obvious example, and the difference is directional rather than a matter of capability. In that model you write a decorated function, and the specification is generated from it. The document is a build output. In Connexion the document is an input: you write it, and the framework configures itself from it.

That changes who can start the work. With Connexion, an API designer can write and review the specification before any handler exists, and the connexion run openapi.yaml command lets that specification be exercised as a mock. With a code-first framework, the specification cannot exist until someone writes the code, so design review and implementation are the same activity.

The cost lands on iteration speed. A code-first framework gives you autocompletion and type checking on the handler signature directly. Connexion gives you a string, operationId, that no type checker validates. Connexion's answer to the drift problem is to make the specification authoritative; FastAPI's answer is to make it automatic. Neither eliminates the other's failure mode, and the choice is really about which artifact your organisation reviews.

## Maintenance, licence and the 2.x to 3.x split

The repository is not archived, and the last push was on 2026-09-07. The most recent releases listed are 3.3.0 and 2.15.1, both dated 2025-10-13, which tells you the 2.x line still receives releases alongside 3.x. That matters for upgrade planning: a project on 2.x is not stranded, but the README's prominent link to the Connexion 3 changes page signals where the framework's direction sits.

The licence is Apache-2.0, declared both in the repository metadata and in the pyproject.toml license field, with a NOTICE file at the top level. Apache-2.0 permits commercial use and modification and includes a patent grant. It also requires that the NOTICE file's attributions be preserved when you redistribute. That is a packaging obligation, not a legal opinion, and if you vendor Connexion into a distribution you should read the licence text rather than rely on this summary.

The upgrade cost is concentrated in the 2.x to 3.x move. The three application classes and the middleware in Connexion 3 differ from the 2.x model, and the README frames FlaskApp partly as a migration aid. The declared Python support in pyproject.toml runs from 3.9 through 3.14, so the version floor is low enough that most current environments qualify.

## Conclusion

Adopt Connexion when the OpenAPI file is the contract you hand to other teams and you want validation, routing and serialization derived from it. Skip it when your specification is produced from code annotations and nobody reads it, because the spec-first workflow only pays off if the file is maintained. Before committing, install connexion[swagger-ui,uvicorn], run the helloworld example from the repository, and confirm that your spec's operationId values resolve to importable Python callables, since that string is the only link between the YAML and your code.

## FAQ

### What is Connexion in Python?

It is a Python web framework for spec-first and api-first development. You describe the API in an OpenAPI or Swagger specification, and Connexion registers the routes, validates requests and responses, parses parameters and serializes return values from that specification.

### How do I install Connexion?

The README gives pip install connexion as the base install. Optional features come as extras: swagger-ui for the documentation console, uvicorn for app.run() during development, and flask for the FlaskApp.

### How does Connexion connect an OpenAPI path to a Python function?

Through the operationId field. The README's example uses operationId: run.post_greeting, which points to a post_greeting function in a module named run. There are no route decorators; app.add_api("openapi.yaml") performs the registration.

### Can Connexion be added to an existing ASGI or WSGI application?

Yes. ConnexionMiddleware can be wrapped around any existing ASGI or WSGI application, which the README presents as the option for adding Connexion's functionality to a service written in a different framework.

### Does Connexion work with Flask?

It does, through the FlaskApp class. The README gives two reasons to choose it: migrating from Connexion 2.x, or wanting to use the Flask ecosystem. The flask extra installs the needed dependency.

## Sources

- [License: Apache-2.0](https://github.com/spec-first/connexion/blob/main/LICENSE)
- [Project website](https://connexion.readthedocs.io/en/latest/)
- [README](https://github.com/spec-first/connexion/blob/main/README.md)
- [Releases](https://github.com/spec-first/connexion/releases)
- [spec-first/connexion on GitHub](https://github.com/spec-first/connexion)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/spec-first-connexion
