Litestar plugin for the UniRate currency-exchange API:
UniRatePlugin— anInitPluginProtocolplugin that provides a shared, asyncUniRateClientto your handlers through Litestar's dependency injection (injected asunirateby default).- Prebuilt route handlers — a
UniRateControllermounted at/unirateexposingGET /unirate/rate,/convert,/currencies, and/vat, with full UniRate error mapping onto Litestar HTTP exceptions. - One HTTP client per app — an
httpx.AsyncClient-backed client opened on demand and closed on shutdown.
UniRate covers 593+ fiat, crypto, and commodity codes. Latest rates,
conversion, currencies, and VAT are on the free tier; historical endpoints
(convert_historical) require Pro.
pip install litestar-unirateOr with uv / Poetry:
uv add litestar-unirate
poetry add litestar-uniratefrom litestar import Litestar, get
from litestar_unirate import UniRateClient, UniRateConfig, UniRatePlugin
app = Litestar(
plugins=[UniRatePlugin(UniRateConfig())], # reads UNIRATE_API_KEY from env
)That alone mounts the prebuilt endpoints:
$ curl 'localhost:8000/unirate/rate?from_currency=USD&to_currency=JPY'
{"rate":151.83}
$ curl 'localhost:8000/unirate/convert?from_currency=USD&to_currency=EUR&amount=100'
{"result":92.5}
$ curl localhost:8000/unirate/currencies
{"currencies":["USD","EUR","GBP", ...]}
$ curl 'localhost:8000/unirate/vat?country=DE'
{"country":"DE","vat_data":{"country_code":"DE","country_name":"Germany","vat_rate":19.0}}
The plugin also injects the client into your own handlers under the unirate
key:
@get("/summary")
async def summary(unirate: UniRateClient) -> dict[str, object]:
return {"usd_eur": await unirate.get_rate("USD", "EUR")}UniRateConfig controls the client and the routes:
UniRateConfig(
api_key=None, # default: $UNIRATE_API_KEY
base_url="https://api.unirateapi.com", # default: production
timeout=30.0, # HTTP timeout (seconds)
dependency_key="unirate", # DI name for the client
register_routes=True, # mount the prebuilt /unirate/* routes
route_path_prefix="/unirate", # where to mount them
)Set register_routes=False to expose only the injectable client and wire your
own handlers.
Note: the prebuilt
UniRateControllerinjects the client under the nameunirate. If you set a customdependency_key, keepregister_routes=False(or use the default key) so the controller resolves its dependency.
The injected UniRateClient is a small async wrapper over UniRate:
| Method | Returns |
|---|---|
get_rate(from_currency="USD", to_currency=None) |
float for a pair, else dict[str, float] |
convert(from_currency, to_currency, amount=1.0) |
float |
get_supported_currencies() |
list[str] |
get_vat_rates(country=None) |
dict (vat_rates map, or vat_data for one country) |
convert_historical(from_currency, to_currency, date, amount=1.0) |
float (Pro) |
The client raises UniRateAPIError (with status_code) on non-2xx responses.
The prebuilt handlers translate those onto Litestar HTTP exceptions:
| UniRate HTTP | Litestar exception | Response |
|---|---|---|
| 400 | ClientException |
400 |
| 401 | NotAuthorizedException |
401 |
| 403 | PermissionDeniedException |
403 (Pro required) |
| 404 | NotFoundException |
404 |
| 429 | TooManyRequestsException |
429 |
| 503 | ServiceUnavailableException |
503 |
| transport / other | HTTPException |
502 |
- Python 3.10 – 3.13
- Litestar ≥ 2.0
- httpx ≥ 0.27
unirate-api— sync UniRate Python client.fastapi-unirate— FastAPI integration.flask-unirate— Flask integration.- Other UniRate integrations: dbt, Airflow, LangChain, MCP server. Full list at https://unirateapi.com.
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: FastAPI · Flask · NestJS · Django / Wagtail · React · tRPC
- Static-site generators: Astro · Eleventy · Hugo
- Data / orchestration: Airflow · dbt · LangChain
- Workflow / no-code: n8n · Google Sheets · MCP server
Get a free API key at unirateapi.com.
MIT