Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MangoLab FX Tool

A small FastAPI service that converts an amount using ECB exchange rates from Frankfurter. It prioritizes a truthful failure over an uncertain financial number.

Install and run

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
./run.sh

Python 3.10 or newer is required.

The service listens on PORT (default 8080). FX_UPSTREAM_BASE is the Frankfurter root URL (default https://api.frankfurter.dev); the service calls its /v1/{date} endpoint and, when failed historical probes are ambiguous, its /v1/currencies metadata endpoint.

PORT=9000 FX_UPSTREAM_BASE=http://localhost:9001 ./run.sh

Run the complete test suite with:

./test.sh

Tests use httpx.MockTransport and never contact the configured upstream or the internet.

Endpoint

GET /tools/convert?amount=250&from=EUR&to=TRY&date=2026-08-28

All four query parameters are required. Currency codes are case-insensitive three-letter ASCII codes. On success:

{
  "amount": 250,
  "from": "EUR",
  "to": "TRY",
  "rate": 47.1234,
  "result": 11780.85,
  "rate_date": "2026-08-28",
  "asked_date": "2026-08-28",
  "source": "ECB via frankfurter.dev"
}

asked_date is always the date supplied by the caller. rate_date is always the publication date read from the validated upstream payload. For an ECB weekend or holiday, the service uses the most recent safely available earlier publication, so these fields can differ. It first allows the historical endpoint to supply a previous rate, then probes at most seven earlier calendar days. A later publication is never used for a historical request.

Amounts must be finite, greater than zero, and have at most two decimal places. Conversion uses Decimal, keeps the upstream rate's full precision, and rounds only the final result to two places using ROUND_HALF_UP. Equal source and target currencies are rejected.

Only validated successful rate lookups are cached in memory. The key is (from, to, asked_date), so different amounts reuse a rate while different dates cannot contaminate each other. The cache lasts for the application process. A successfully validated provider currency catalog is also cached in process; no hardcoded currency list is used.

Errors

Every failure is non-2xx and has exactly this shape:

{"error": "invalid_amount", "message": "Amount must be greater than zero."}
Status Code Meaning
404/405/422 invalid_request A required query parameter/date is missing or malformed, or the operation is unavailable.
422 invalid_amount Amount is invalid, non-positive, non-finite, over-precise, or too large to calculate safely.
422 invalid_currency A code has invalid syntax or the upstream does not support it.
422 same_currency Source and target are equal after normalization.
422 future_date The requested date is in the future.
404 date_out_of_range All bounded historical probes were outside available history.
404 rate_not_available Valid historical responses contained no safely usable target rate.
504 upstream_timeout The upstream exceeded the five-second timeout.
502 upstream_unavailable The upstream could not be reached.
502 upstream_error The upstream returned a server or unexpected HTTP error.
502 invalid_upstream_response JSON, base, publication date, rates, or rate value failed validation.
500 internal_error An unexpected failure prevented a safe conversion.

Upstream failures never become successful zero-value conversions. Frankfurter v1 uses 404 both for unsupported currencies and unavailable historical dates, so after a failed bounded search the service consults the configured upstream's currency catalog. A missing requested code returns invalid_currency; supported codes with all historical probes missing return date_out_of_range; valid historical payloads without the target rate return rate_not_available. A fake upstream that does not implement the catalog may return 404, in which case the bounded historical classification is preserved. Catalog failures are mapped to the same upstream error codes listed above.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages