๐ Two of my biggest passions in life are running races and traveling. I often find myself scouring multiple sites to find races worldwide. While I love the thrill of planning, the process of navigating scattered, outdated websites is frustrating and inefficient. After years of dealing with this, I finally decided to start build the race finder app I had been putting off for far too long.
My goal is to create a centralized, well-structured API that aggregates race data from around the world, making it easier for athletes to discover races that fit their schedules and preferences.
This blog series will walk through my journey of building a race finder API (aka RaceGriot) from designing the REST API to integrating GraphQL, aggregating data sources, and beyond.
Choosing the tech stack for my API
The natural starting point for my project was to build a REST API that could eventually support various frontends and services. For the MVP, I focused on a simple yet functional foundation with the following characteristics:
- backed by a static JSON file to store race data.
- supports GET requests to retrieve all race data.
- includes basic filtering by location (City, State, Country)
- publicly accessible
๐ API breakdown: the key components
To build a reliable API, you need:
- ๐ A strong framework to handle requests and responses
- ๐ A storage system to manage data
- ๐ A deployment strategy to make it accessible
Each component plays a crucial role in ensuring the API is scalable, efficient, and easy to maintain. Here’s what I did for my MVP.
1) API framework: handling requests and responses
The API framework determines how data is requested and returned. I decided to build RaceGriot in Python, so I needed a lightweight, scalable, and developer-friendly framework. Here are the various frameworks I considered:
| Framework | Pros | Cons |
|---|---|---|
| Django REST | Full-featured, great for large projects, built-in authentication | Heavy for a simple API, requires Django ORM |
| Flask | Lightweight, flexible, widely used | No built-in async support, manual API docs setup |
| Express.js | Fast, great for Node.js apps | Not Python-based, different ecosystem |
| FastAPI | High-performance, async support, automatic OpenAPI docs | Newer, smaller community |
โ Final Choice: I chose FastAPI for its balance of speed, simplicity, and flexibility while staying in Python.
2) Choosing the right server
Since FastAPI is asynchronous, it requires an ASGI (Asynchronous Server Gateway Interface) server to handle requests efficiently. Here are some options I considered.
| Server | Type | Pros | Cons |
|---|---|---|---|
| Uvicorn | ASGI | Fast & lightweight Native async support Built-in OpenAPI docs | Needs Gunicorn for multiple workers |
| Daphne | ASGI | Great for WebSockets Good Django integration | Slower for standard APIs |
| Hypercorn | ASGI | Multiprotocol support (HTTP/2, WebSockets) | Heavier than Uvicorn |
โ Final Choice: I chose Uvicorn because it is optimized for FastAPIโs event-driven architecture.
3) Storing race data
For the MVP, I kept it simple by using a static JSON file rather than introducing the complexity of ingesting data from multiple sources. Those enhancements will come later. Hereโs a snippet of the JSON file:
{
"races": [
{
"id": 1,
"name": "Boston Marathon",
"location": {
"city": "Boston",
"state": "MA",
"country": "USA",
"zip_code": "02116"
},
"date": "2025-04-21",
"type": "Marathon",
"website": "https://www.baa.org/",
"registration_link": "https://www.baa.org/races/boston-marathon/enter"
}
]
}
4) Making the API public
The API needs to be deployed to make it publicly accessible. Here are some options I evaluated.
| Platform | Pros | Cons |
|---|---|---|
| AWS | Scalable, industry standard | Complex setup, higher cost |
| Heroku | Simple, GitHub integration | Expensive at scale, limited free tier |
| Vercel | Great for frontends | Not ideal for backend APIs |
| DigitalOcean | Affordable, balance of control | Requires more setup |
| Render | Auto-deployments, free tier, managed services | Fewer custom options vs AWS |
โ Final Choice: I chose Render primarily because of its ease of use, automation, and scalability: free tier (ideal for my MVP) and One-click GitHub deploys
Recap: RaceGriotโs API Tech Stack for MVP
- VSCode – Code editor
- GitHub – Source control
- FastAPI โ API framework
- Uvicorn โ ASGI server
- Static JSON file โ Temporary race data storage
- Render โ Deployment platform
With the tech stack now solidified, let’s get to building! Check the next post in the series for that. ๐