A fast, modern API for geocoding UK postcodes built with FastAPI.
- ⚡ Fast: All postcode data loaded into memory for instant O(1) lookups
- 🚀 Modern: Built with FastAPI, includes automatic OpenAPI documentation
- 📊 Observable: Integrated with Logfire for monitoring and debugging
- 🔄 Auto-updating: GitHub Actions automatically updates postcode data weekly
- ✅ Well-tested: Comprehensive test suite with pytest
- 🛠️ Developer-friendly: Uses uv for fast dependency management
- Python 3.12+
- uv (recommended) or pip
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone the repository
git clone https://github.com/tutorcruncher/uk-postcode-api.git
cd uk-postcode-api
# Install dependencies
make install-dev
# Set your authentication token
export AUTH_TOKEN="your-secret-token-here"
# Generate postcode data files (downloads ~2GB, processes to ~33MB)
make update-postcodes# Development server with auto-reload
make run-dev
# Or use uvicorn directly
uv run uvicorn app.main:app --reload --port 8000The API will be available at http://localhost:8000
- API Documentation: http://localhost:8000/docs
- Alternative docs: http://localhost:8000/redoc
- Health check: http://localhost:8000/health
curl -X POST http://localhost:8000/api/ \
-H "Authorization: Token your-secret-token-here" \
-H "Content-Type: application/json" \
-d '["SW8 5EL", "W1J 7BU", "N7 7AJ"]'Response:
{
"results": {
"SW8 5EL": [51.475, -0.121],
"W1J 7BU": [51.509, -0.143],
"N7 7AJ": [51.556, -0.118]
},
"errors": {}
}make install # Install production dependencies
make install-dev # Install with dev dependencies
make test # Run tests
make test-cov # Run tests with coverage
make lint # Check code style
make format # Format code with ruff
make run-dev # Run development server
make update-postcodes # Download and process latest postcode data
make clean # Clean cache files# Run all tests
make test
# Run with coverage
make test-cov
# Run specific test file
uv run pytest tests/test_postcodes.py -vThis project uses Ruff for linting and formatting:
# Check for issues
make lint
# Auto-fix issues
make formatThe app is ready to deploy on Heroku:
# Create Heroku app
heroku create your-app-name
# Set config
heroku config:set AUTH_TOKEN="your-secret-token"
# Deploy
git push heroku masterAUTH_TOKEN(required): Authentication token for API accessSENTRY_DSN(optional): Sentry DSN for error trackingLOGFIRE_TOKEN(optional): Logfire token for observabilityLOGFIRE_ENVIRONMENT(optional): Environment name (default: development)PORT(optional): Port to run on (default: 8000)
The postcode data is sourced from:
- doogal.co.uk - Primary source
The raw CSV is ~2.0GB uncompressed, but is compressed to just ~33MB using msgpack format (60x compression).
Postcode data is automatically updated weekly via GitHub Actions. The workflow:
- Downloads the latest postcode CSV (~2GB)
- Processes and compresses it to msgpack format (~33MB)
- Creates a pull request with the updates
- You review and merge
You can also trigger updates manually:
make update-postcodesuk-postcode-api/
├── app/
│ ├── api/ # API endpoints
│ ├── core/ # Configuration and logging
│ ├── services/ # Business logic
│ └── data/ # Postcode msgpack files
├── tests/ # Test suite
├── scripts/ # Utility scripts
└── .github/workflows/ # CI/CD automation
- Startup: Loads 1.7M postcodes into memory in ~2 seconds
- Memory: ~200MB RAM when all data is loaded (perfect for Heroku 1X with 512MB)
- Lookup speed: O(1) dict lookup, typically <1ms per postcode
- Throughput: Handles thousands of requests per second
The API maintains backward compatibility with the original Flask-based API:
- Same endpoint (
/api/) - Same request/response format
- Same authentication mechanism
- Just much faster! 🚀
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Run
make lintandmake test - Submit a pull request
MIT License - see LICENSE file for details.
Built with:
- FastAPI - Modern web framework
- uv - Fast Python package installer
- Logfire - Observability platform
- Ruff - Fast Python linter
Original version by TutorCruncher. Modernized in 2024.