DEV Community

Alex
Alex

Posted on

I built a Football Player Data API with Node.js (rate limiting, caching, filtering) — here’s what I learned

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:

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)

Collapse
 
ap_ufd profile image
Alex

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!!!