FastAPIPostmanPydantic

FastAPI to Postman: better than importing openapi.json

Importing /openapi.json gives you URLs. Here's how to generate a FastAPI Postman collection with a working OAuth2 login, saved tokens, valid Pydantic examples and environments.

FastAPI gives you an OpenAPI document for free, and Postman can import it. So why use anything else? Because the imported collection is where the work starts: you still have to wire up login, copy tokens, create environments and fix example bodies that fail validation.

This post compares the two approaches on the same app and shows how routeman produces a collection you can use straight away.

The example app

from fastapi import FastAPI, Depends, Query
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel, Field

app = FastAPI(title="Shop API")
oauth = OAuth2PasswordBearer(tokenUrl="/auth/token")

class ProductIn(BaseModel):
    name: str = Field(min_length=2, max_length=80)
    price: float = Field(gt=0)
    sku: str

@app.post("/auth/token", tags=["auth"])
def token(): ...

@app.get("/products", tags=["products"])
def list_products(page: int = 1, search: str | None = Query(None)): ...

@app.post("/products", tags=["products"])
def create_product(p: ProductIn, user=Depends(oauth)): ...

@app.get("/products/{product_id}", tags=["products"])
def get_product(product_id: int, user=Depends(oauth)): ...

Option 1: import openapi.json

Start the server, then in Postman choose Import and paste http://localhost:8000/openapi.json. You get requests grouped by tag, which is a good start. But:

  • Login isn't automated. You send the token request, copy access_token from the response and paste it into the auth settings by hand, and again every time it expires.
  • No environments. Switching between local and staging means editing URLs or building environments yourself.
  • Hidden routes are missing. Anything with include_in_schema=False, often internal or admin endpoints, is left out.
  • No tests. The Collection Runner has nothing to assert.

Option 2: generate with routeman

$ pip install routeman
$ routeman generate -a main:app
✓ fastapi: 4 requests (2 POST, 2 GET)
✓ auth: bearer (login: POST /auth/token)
✓ wrote postman/demo-api.postman_collection.json
✓ wrote postman/demo-api.local.postman_environment.json
  done in 0.31s - import the files in Postman (File → Import)

No server needs to run. routeman builds the OpenAPI document in memory and also reads the route table. Here's what it adds:

A login request that saves the token

routeman saw OAuth2PasswordBearer(tokenUrl="/auth/token"), so Auth › Token gets a test script. After you send it, the script searches the response for the token (including nested keys) and runs:

pm.environment.set('access_token', access);
pm.environment.set('refresh_token', refresh);
pm.test('login returned a token', ...)

The collection's auth is Bearer {{access_token}}, and the login request itself is No Auth. Send login once and everything else works.

Bodies that pass Pydantic validation

The generated Create Product body:

{
  "name": "John Doe",
  "price": 1.5,
  "sku": "string"
}

price is 1.5 because of gt=0, so a zero would be rejected with a 422. name fits min_length/max_length and reads like a name. routeman also respects Literal/Enum values, regex patterns and well-known field names such as email.

Query and path parameters

List Products has page=1 and search, added but disabled, so the default request matches the default behaviour. {{product_id}} is an environment variable (default 1) that you set once from a list response.

Environments and smoke tests

The environment holds base_url, secret access_token/refresh_token/password and the path ids. Add more servers with -e staging=https://staging.example.com. Every request carries a "no server error" test, so the Collection Runner flags any 5xx.

Forms, files and headers

Endpoints using Form(...) become x-www-form-urlencoded requests, File()/UploadFile become multipart with a file picker, and Header() parameters are added as request headers. APIKeyHeader security becomes Postman API-key auth on the right header.

Where's my app?

routeman looks for the FastAPI() instance in common locations. Otherwise, point to it:

routeman generate -a app.main:app
routeman generate -a "app.factory:create_app()"
routeman init          # remember it in routeman.toml

Summary

openapi.json importrouteman
Needs a running serverYes (or an exported file)No
Login saves tokenNoYes
Hidden routesNoYes
EnvironmentsNoOne per server
Smoke testsNoOn every request

Keep /docs for interactive documentation and use routeman for the Postman collection your team works in every day. More on the FastAPI page.

Try routeman on your project

$ pip install routeman
$ routeman generate

Read the docs → Ask a question