add /stats-info/{sport}/{division} endpoint#34
Conversation
henrygd
left a comment
There was a problem hiding this comment.
Thank you. I'm really swamped and don't have time to go through line by line at the moment.
If possible, it would be better for me if this could be split this into two PRs. One for the new feature and one for changes to existing code that aren't directly related to the new feature.
Regarding the new endpoint: Is it incompatible currently with other sports, or is soccer just the only one that you've tested with?
How many requests do we need to make upstream in order to gather the data for a specific sport and division? Is it just the one request to ncaa.com/stats/sport/division and then gathering the values from the select fields?
Is there a reason for using a generator script rather than fetching the values when the first user request comes in and saving it in a cache like the other endpoints? It doesn't seem like that expensive of an operation. I know these values rarely change, so we can add a new longer term cache like 24 hours.
Returns the list of available stat categories (individual + team) for
a given sport and division, so API consumers can discover valid
{path} values for the existing /stats endpoint without having to
click around on ncaa.com.
Response shape:
{
"individual": [{ "id": "5", "label": "Goals Per Game", "path": "individual/5" }, ...],
"team": [{ "id": "30", "label": "Scoring Offense", "path": "team/30" }, ...]
}
Implementation notes:
- Fetches https://www.ncaa.com/stats/{sport}/{division} on cache miss,
parses the two <select id="select-container-{individual|team}">
dropdowns with linkedom. One upstream request per sport/division.
- 24h cache (new cache_24h) since stat categories rarely change. Returns
Cache-Control: public, max-age=86400.
- Works for any sport/division NCAA.com supports — the parser doesn't
special-case soccer. Tested against soccer (men/women, D1/D2/D3)
and basketball-men/d1.
Files:
- src/stats/parser.ts — reusable dropdown parser
- src/types/stats.ts — shared types
- src/index.ts — endpoint handler + cache_24h + onBeforeHandle update
- src/openapi.ts — spec entry for /stats-info, plus description update
on /stats {path} param pointing users at /stats-info
- test/index.test.ts — integration tests (live NCAA.com)
- test/parser.test.ts — HTML fixture tests for the parser
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69bef35 to
3d0729a
Compare
Yes 👍 I can get a new PR up that splits the two to make it easier for review
Not incompatible, but I only fully tested it out with soccer. The
Yes just that one request and then parse the two
Good point. I'll update the PR to follow those other endpoints pattern of the save in cache delete the script + generated json. Also, will add in a 24 hour cache to go with |
henrygd
left a comment
There was a problem hiding this comment.
Thanks a lot, this should be a useful feature.
I made a few small updates. The most significant is changing the endpoint to be /stats/{sport}/{division}. So it's the same as the existing /stats route, but without the year and path added on.
The public API and docker image will be updated in a few minutes.


Summary
Adds
/stats-info/{sport}/{division}— a discovery endpoint that returns the available stat categories (individual + team) for a given sport and division. Lets API consumers find valid{path}values for the existing/statsendpoint without having to click around on ncaa.com.Response shape
{ "individual": [ { "id": "5", "label": "Goals Per Game", "path": "individual/5" }, { "id": "6", "label": "Assists Per Game", "path": "individual/6" } ], "team": [ { "id": "30", "label": "Scoring Offense", "path": "team/30" } ] }How it works
https://www.ncaa.com/stats/{sport}/{division}on cache miss<select id=\"select-container-{individual|team}\">dropdowns withlinkedomcache_24hbucket (Cache-Control: public, max-age=86400) since stat categories rarely changeSport support
Works for any sport/division NCAA.com supports — the parser doesn't special-case soccer. Tested against soccer (men/women, D1/D2/D3), icehockey-men/d1, and football/fbs.
Files
src/stats/parser.tssrc/types/stats.tssrc/index.tscache_24h+onBeforeHandleupdated to setmax-age=86400for 24h cachesrc/openapi.ts/stats-info; description added to/stats{path}parameter pointing users at/stats-infotest/index.test.tstest/parser.test.tsHardening separated
Per #34 review feedback, the unrelated security/code-quality fixes from the original PR have been moved to a separate draft: #35. This PR is now feature-only.
Test plan
Stats infoblock removed and replaced)icehockey-men/d1andfootball/fbs+ screenshots added belowAdditional Test Items from PR Reviewer
Screenshots
🤖 Generated with Claude Code