Over the past few months, I kept running into the same problem while building side projects.
I like creating football related tools, things like squad builders, player comparison apps, and small analytics dashboards.
But every time I started a new project, I hit the same wall: Getting clean, structured football player data is harder than it should be.
Most of the available options are:
- scraped from websites
- inconsistent between sources
- outdated
- or just painful to work with
After dealing with this a few too many times, I decided to stop relying on external data and build my own API!
The stack
I kept things simple but production-oriented:
- Node.js + express js
- MySQL
- In-memory caching
- Manual rate limiting
Structured relational data
What I built *
A REST API that serves structured football player data (similar to Ultimate Team style datasets).
Example endpoint:
GET /ufd/2021/players
Example response (simplified):
{
"name": "Ronaldo",
"fullname": "C. Ronaldo dos Santos Aveiro",
"birth_date": "1985-02-05",
"overall_index": 99,
"position": "ST",
"foot": "Right",
"club": "Piemonte Calcio",
"league": "Serie A TIM",
"country": "Portugal",
"speed_indexOverallStat": 98,
"shooting_scoreOverallStat": 99,
"passing_indexOverallStat": 92,
"dribble_indexOverallStat": 99,
"defensive_indexOverallStat": 43,
"physical_indexOverallStat": 94,
}
The goal make data easy to consume for developers building football apps.
*** One challenge: rate limiting ***
Since I wanted this to behave like a real API, I implemented a simple rate limiting system per API key.
Here’s a simplified version:
const rateLimitMap = new Map();
const WINDOW = 60 * 1000;
function checkRateLimit(apiKey, limit) {
const now = Date.now();
const user = rateLimitMap.get(apiKey) || { count: 0, start: now };
if (now - user.start > WINDOW) {
user.count = 0;
user.start = now;
}
user.count++;
rateLimitMap.set(apiKey, user);
return user.count <= limit;
}
Not perfect, but good enough for a first version.
*** Caching layer ***
To avoid hitting the database on every request, I added a simple in-memory cache:
const cache = new Map();
const TTL = 60 * 60 * 1000;
function getCache(key) {
const entry = cache.get(key);
if (!entry) return null;
if (Date.now() > entry.expiry) {
cache.delete(key);
return null;
}
return entry.data;
}
This alone made a huge difference in performance.
*** Filtering & search ***
I also added a basic search system:
LOWER(p.name) LIKE ?
OR LOWER(p.fullname) LIKE ?
And dynamically build queries depending on filters and pagination.
*** Data modeling ***
One of the most interesting parts was structuring the data.
Instead of returning raw database rows, I grouped stats into categories:
pace
shooting
passing
dribbling
defense
physical
This makes the API much easier to use on the frontend.
*** What’s not perfect (yet) ***
There are still things I want to improve:
Move caching to Redis
Improve query performance at scale
Add better filtering (by league, club, rating, etc.)
Clean up some stat naming inconsistencies
*** What I learned ***
A few takeaways from building this:
You don’t need a complex stack to build something useful
Data modeling matters more than you think
Even simple caching can massively improve performance
Building your own tools is sometimes faster than fighting bad ones
*** Looking for feedback ***
If you’ve built APIs before, I’d love your thoughts:
Would you change how rate limiting is handled?
Is in-memory caching a bad idea early on?
Any suggestions for structuring this kind of data better?
If you're building something similar, happy to share more details.
***************** Project links *****************
If you're interested in using it or exploring more:
- ⚡Landing page: https://ufdapi.netlify.app/
- 🌐API on RapidAPI (free tier available): https://rapidapi.com/ultimate-football-data-api-ultimate-football-data-api-default/api/ultimate-football-data-api
- 💻 GitHub repository: https://github.com/alexpineda99/ultimate-football-data-api
I'm still actively improving it, so any feedback is really appreciated!
If you’re building something football-related, I’d be happy to hear about it!
Thanks for reading 🙌
Top comments (1)
If anyone is building football-related apps (or APIs in general), Id love to connect and exchange ideas!
Also happy to give free access for testing if you want to try it out!!!