fastapi-unirate
FastAPI integration for the UniRate currency-exchange API:
- Async dependency —
Depends(get_unirate_client)plus a typedUniRateDepalias for path-operation signatures. - Lifespan helper — one shared
httpx.AsyncClient-backed UniRate client per app, opened on startup and closed on shutdown. MoneyPydantic type — amount + currency pair that round-trips through OpenAPI schemas.CurrencyConversionMiddleware— auto-rewrites Money-shaped values in JSON responses to a request-scoped target currency (?currency=EUR).
UniRate covers 593+ fiat, crypto, and commodity codes. Latest rates and
conversion are on the free tier; historical endpoints
(convert_historical) require Pro.
Install
pip install fastapi-unirate
Or with uv / Poetry:
uv add fastapi-unirate
poetry add fastapi-unirate
Quick start
import os
from fastapi import FastAPI
from fastapi_unirate import (
CurrencyConversionMiddleware,
Money,
UniRateDep,
unirate_lifespan,
)
app = FastAPI(lifespan=unirate_lifespan()) # reads UNIRATE_API_KEY from env
app.add_middleware(CurrencyConversionMiddleware)
@app.get("/products/widget")
async def get_widget() -> dict[str, Money]:
return {"price": Money(amount=19.99, currency="USD")}
@app.get("/rate/{base}/{quote}")
async def rate(base: str, quote: str, client: UniRateDep) -> dict[str, float]:
return {"rate": await client.get_rate(base, quote)}
Then:
$ curl localhost:8000/products/widget
{"price":{"amount":19.99,"currency":"USD"}}
$ curl localhost:8000/products/widget?currency=EUR
{"price":{"amount":18.42,"currency":"EUR"}}
$ curl localhost:8000/rate/USD/JPY
{"rate":151.83}
The middleware finds every {"amount": <number>, "currency": "<code>"}
shape — top-level, nested, or inside lists — and rewrites it. Conversions
are de-duplicated per request and run concurrently.
Configuration
unirate_lifespan accepts overrides:
app = FastAPI(
lifespan=unirate_lifespan(
api_key="...", # default: $UNIRATE_API_KEY
base_url="https://api.unirateapi.com", # default: production
timeout=15.0, # default: 30s
)
)
CurrencyConversionMiddleware accepts the query-parameter name and an
explicit client (mostly for testing):
app.add_middleware(
CurrencyConversionMiddleware,
query_param="display_currency",
)
Why a middleware?
The dossier sketched two integration shapes — DI and middleware — and both pull their weight:
- The DI provider is the right tool when a handler explicitly wants to
call
convert()orget_rate(). - The middleware is the right tool when a service has a stable
Money-shaped response and wants to expose one?currency=knob to clients without rewriting every handler.
You can use either, or both together (as in the quick-start example).
Errors
The client raises UniRateAPIError on non-2xx responses (with
status_code set). Common cases:
| HTTP | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 403 | Pro subscription required (historical, commodities) |
| 404 | Currency not found |
| 429 | Rate limit exceeded |
The middleware swallows UniRateAPIError and passes the original
response through unchanged — so an upstream UniRate outage never becomes
a 500 on your service.
Compatibility
- Python 3.9 – 3.13
- FastAPI ≥ 0.100
- Pydantic ≥ 2.0
Related
unirate-api— sync UniRate Python client (this package vendors a small async equivalent so it doesn't pull inrequests).langchain-unirate— LangChain partner package.- Other UniRate integrations: dbt, Airflow, n8n, Raycast, MCP server. Full list at https://unirateapi.com.
Other UniRate clients
UniRate ships official client libraries and framework integrations across the ecosystem. The repos below are all maintained under the UniRate-API org.
- Languages: Python · Node.js / TypeScript · Go · Rust · Java · Ruby · PHP · .NET · Swift
- Web frameworks: NestJS · Django / Wagtail · FastAPI · Flask · React · tRPC
- Static-site generators: Astro · Eleventy · Hugo
- Data / orchestration: Airflow · dbt · LangChain
- Workflow / no-code: n8n · Google Sheets · MCP server
- Editors / tools: VS Code · Obsidian
- Specialty bridges: NodaMoney (.NET)
Get a free API key at unirateapi.com.
License
MIT
Metadata
Release files for fastapi-unirate 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastapi_unirate-0.1.1.tar.gz | 13.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastapi_unirate-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.4 kB
Release files / fastapi_unirate-0.1.1.tar.gz
| Download URL | fastapi_unirate-0.1.1.tar.gz |
|---|---|
| Size | 13.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f7f7e2c800e620e7a6fddf4354224fa0086ed85af9e83a828811b15151324dd9
|
|
BLAKE2b-256 checksum How to use checksums |
d21f02024db05fde09523773b80c471b3a90ff00227ee655e58f9d53724b3cdd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logRelease files / fastapi_unirate-0.1.1-py3-none-any.whl
| Download URL | fastapi_unirate-0.1.1-py3-none-any.whl |
|---|---|
| Size | 11.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
91895f95c559336bc60d3c34d488684294ba5588e39f32aaf3220f9a663b3e8b
|
|
BLAKE2b-256 checksum How to use checksums |
b9e22286f6683d578402d7f6045f6c26a24cdabc10de86ed8a787d32adfa1830
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency log