Skip to content

FastAPI service for fetching and serving daily currency conversion rates with automatic scheduling, database-agnostic design, and REST API

Notifications You must be signed in to change notification settings

rxhuljoshi/currency-conversion-api

Repository files navigation

Currency Rate Fetcher

A production-grade, database-agnostic FastAPI service that fetches daily currency conversion rates for all supported currencies. The service automatically fetches rates twice daily (00:00 and 12:00 UTC) and also on startup if no rates exist for the current day, ensuring data is always available. It stores only the latest rates and is fully compatible with Supabase Postgres, local Postgres, or any SQL database.

Features

  • Database Agnostic: Works with Supabase, local Postgres, Neon, Railway, RDS, or any PostgreSQL database
  • Automatic Scheduling: Fetches rates twice daily (00:00 and 12:00 UTC) and on startup if needed
  • Flexible Currency Selection: Enter any currency code to get its value converted to all other currencies in JSON format; simple and intuitive API
  • Latest Rates Only: Automatically removes old rates, keeping only the most recent data
  • Fully Async: Built with async/await throughout for optimal performance
  • Production Ready: Includes health checks, error handling, and proper logging
  • Docker Support: Ready for containerization and deployment
  • Type Safe: Fully typed with Pydantic v2 and SQLAlchemy 2.0

Tech Stack

  • FastAPI - Modern, fast web framework
  • SQLAlchemy 2.0 - Async ORM with async engine and sessions
  • asyncpg - High-performance async PostgreSQL driver
  • httpx - Async HTTP client for API requests
  • APScheduler - Async job scheduler
  • Pydantic v2 - Data validation and settings management
  • Alembic - Database migrations (optional)

Project Structure

.
├── app/
│   ├── main.py              # FastAPI application entry point
│   ├── core/
│   │   ├── config.py       # Configuration and settings
│   │   └── database.py     # Database connection and session management
│   ├── models/
│   │   └── exchange_rate.py # SQLAlchemy model
│   ├── services/
│   │   └── fx_service.py   # Currency rate fetching service
│   ├── scheduler/
│   │   └── jobs.py         # Scheduled jobs
│   └── api/
│       └── routes.py        # API endpoints
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── .env.example
└── README.md

Quick Start

Prerequisites

  • Python 3.11+
  • PostgreSQL database (local or cloud-hosted)
  • ExchangeRate API key (Get one here)

Installation

  1. Clone the repository
git clone <repository-url>
cd "Daily Currency Conversion Rate Fetcher"
  1. Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
  1. Install dependencies
pip install -r requirements.txt
  1. Configure environment variables
cp .env.example .env

Edit .env with your configuration:

DATABASE_URL=postgresql+asyncpg://username:password@localhost:5432/currency_rates
FX_API_KEY=your_api_key_here
FX_API_BASE_URL=https://v6.exchangerate-api.com/v6
APP_ENV=development
  1. Run the application
python -m uvicorn app.main:app --reload

The service will be available at http://localhost:8000

  • API Documentation: http://localhost:8000/docs
  • Health Check: http://localhost:8000/api/v1/health

Database Setup

Local PostgreSQL

  1. Install PostgreSQL (if not already installed)
# macOS
brew install postgresql
brew services start postgresql

# Ubuntu/Debian
sudo apt-get install postgresql postgresql-contrib
sudo systemctl start postgresql
  1. Create database
createdb currency_rates
  1. Update .env
DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:5432/currency_rates

Supabase Setup

  1. Create a Supabase project at supabase.com

  2. Get your connection string

    • Go to Project Settings → Database
    • Copy the connection string (either Transaction Pooler or Direct Connection)
    • Format: postgresql+asyncpg://postgres:[YOUR-PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres
  3. Update .env

DATABASE_URL=postgresql+asyncpg://postgres:your_password@db.xxxxx.supabase.co:5432/postgres

Note: The service treats Supabase as a standard PostgreSQL database. No Supabase SDK is required.

Other Cloud Providers

The service works with any PostgreSQL-compatible database:

  • Neon: postgresql+asyncpg://user:pass@ep-xxx.us-east-1.aws.neon.tech/neondb
  • Railway: Use the provided PostgreSQL connection string
  • AWS RDS: Standard PostgreSQL connection string
  • Google Cloud SQL: PostgreSQL connection string

API Endpoints

Health Check

GET /api/v1/health

Returns service and database connectivity status.

Response:

{
  "status": "healthy",
  "service": "currency-rate-fetcher",
  "database": "connected"
}

Get Currency Conversions

GET /api/v1/rates/{currency}
GET /api/v1/rates?currency=EUR

Returns conversion rates from the specified currency to all other available currencies.

Enter a currency code (e.g., EUR, USD, GBP) and get its value converted to all other currencies in JSON format.

Examples:

# Get EUR converted to all other currencies
GET /api/v1/rates/EUR

# Get USD converted to all other currencies
GET /api/v1/rates/USD

# Get GBP converted to all other currencies (using query parameter)
GET /api/v1/rates?currency=GBP

# Get stored rates (default: USD base) - no parameter
GET /api/v1/rates

Response (currency conversions):

{
  "from_currency": "EUR",
  "conversions": {
    "USD": 1.18,
    "GBP": 0.86,
    "JPY": 129.79,
    "AUD": 1.65,
    "CAD": 1.48,
    ...
  },
  "fetched_at": "2026-01-24T16:30:00.000000",
  "total_currencies": 162,
  "message": "1 EUR equals the following amounts in other currencies:"
}

Response (stored rates - default USD):

{
  "from_currency": "USD",
  "conversions": {
    "EUR": 0.85,
    "GBP": 0.73,
    "JPY": 110.25,
    "AUD": 1.40,
    "CAD": 1.26,
    ...
  },
  "fetched_at": "2026-01-24T12:00:00.000000",
  "total_currencies": 162,
  "message": "1 USD equals the following amounts in other currencies:",
  "source": "stored"
}

Usage: Simply enter the currency code you want to convert from, and the API returns a JSON object with all conversion rates to other currencies, making it easy to select and use the rates you need.

Docker Deployment

Using Docker Compose

  1. Configure environment
cp .env.example .env
# Edit .env with your settings
  1. Start services
docker-compose up -d

This will start:

  • The FastAPI application on port 8000
  • A PostgreSQL database on port 5432
  1. View logs
docker-compose logs -f currency-fetcher
  1. Stop services
docker-compose down

Using Docker Only

  1. Build the image
docker build -t currency-fetcher .
  1. Run the container
docker run -d \
  --name currency-fetcher \
  -p 8000:8000 \
  --env-file .env \
  currency-fetcher

Scheduling

The service automatically fetches currency rates twice daily:

  • 00:00 UTC (midnight)
  • 12:00 UTC (noon)

Startup Behavior:

  • When the server starts, it automatically checks if rates exist for today
  • If no rates are found for the current day, it immediately fetches and stores them
  • This ensures the API has data available right away, even if the server is started outside the scheduled times

The scheduler:

  • Starts automatically when the application starts
  • Is idempotent (no duplicate jobs on reload)
  • Handles missed executions gracefully (5-minute grace period)
  • Only stores the latest rates (deletes previous entries)

Manual Trigger

To manually trigger a rate fetch (for testing), you can:

  1. Use the scheduler directly (in Python):
from app.scheduler.jobs import currency_job
await currency_job.fetch_and_store_rates()
  1. Or restart the service - the first fetch happens on startup

Environment Variables

Variable Description Required Default
DATABASE_URL PostgreSQL connection string Yes -
FX_API_KEY ExchangeRate API key Yes -
FX_API_BASE_URL Base URL for FX API No https://v6.exchangerate-api.com/v6
APP_ENV Application environment No development

Database Schema

The service creates a single table:

exchange_rates

Column Type Description
id UUID (String) Primary key
base_currency VARCHAR Base currency (e.g., "USD")
rates JSON/JSONB Dictionary of currency rates
fetched_at TIMESTAMP WITH TIME ZONE When rates were fetched (UTC)

Note: Only one row exists at any time. New fetches replace the previous row.

Development

Running in Development Mode

APP_ENV=development python -m uvicorn app.main:app --reload

Code Quality

The codebase follows these principles:

  • Fully async: All I/O operations use async/await
  • Type hints: All functions and classes are fully typed
  • Clean architecture: Separation of concerns (models, services, API, scheduler)
  • Error handling: Comprehensive error handling and logging
  • Database agnostic: No vendor-specific code

Testing the API

# Health check
curl http://localhost:8000/api/v1/health

# Get all rates
curl http://localhost:8000/api/v1/rates

# Get specific currency
curl http://localhost:8000/api/v1/rates/EUR

Deployment

Production Considerations

  1. Environment Variables: Use secure secret management (e.g., environment variables, secrets manager)

  2. Database: Use a managed PostgreSQL service (Supabase, Neon, RDS, etc.)

  3. CORS: Update CORS settings in app/main.py for production:

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourdomain.com"],  # Specific origins
    allow_credentials=True,
    allow_methods=["GET"],
    allow_headers=["*"],
)
  1. Logging: Configure proper logging for production (e.g., structured logging, log aggregation)

  2. Monitoring: Set up health check monitoring for the /api/v1/health endpoint

  3. Scaling: The service is stateless and can be horizontally scaled

Deployment Platforms

  • Railway: Connect your GitHub repo and set environment variables
  • Render: Deploy from GitHub with PostgreSQL addon
  • Fly.io: Use flyctl to deploy
  • AWS/GCP/Azure: Use container services (ECS, Cloud Run, Container Instances)
  • Heroku: Use Heroku Postgres and deploy via Git

Troubleshooting

Database Connection Issues

  • Verify DATABASE_URL format: postgresql+asyncpg://user:pass@host:port/db
  • Check database is accessible from your network
  • For Supabase: Ensure you're using the correct connection string (pooler vs direct)

API Key Issues

  • Verify FX_API_KEY is set correctly
  • Check API key is valid and has sufficient quota
  • Review logs for API error messages

Scheduler Not Running

  • Check application logs for scheduler startup messages
  • Verify the scheduler started: Look for "Currency rate scheduler started" in logs
  • Ensure the application is running continuously (not just for a single request)

No Rates Available

  • Wait for the scheduled fetch (00:00 or 12:00 UTC)
  • Manually trigger a fetch (see Scheduling section)
  • Check logs for fetch errors

License

This project is open-source and available for use under the MIT License.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues, questions, or contributions, please open an issue on the repository.

About

FastAPI service for fetching and serving daily currency conversion rates with automatic scheduling, database-agnostic design, and REST API

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published