FantasyWiki API Naming Rules
1. Identifiers in URLs
- Do not expose sensitive identifiers (e.g.
playerId) in routes if the resource is not meant to be searchable and viewable for normal users. - Use
:idin paths only when:- the resource is publicly or shareably visible (leagues, teams on leaderboards, articles), or
- the endpoint is an admin/staff endpoint with elevated permissions.
- For the current player, never require
playerIdin the URL; the backend must resolve identity from the session/JWT.
2. Plural for collections
Use plural nouns for collections:
GET /api/v1/players– list players (if that concept exists and is allowed)POST /api/v1/players– create a new playerGET /api/v1/leagues– list leaguesGET /api/v1/articles– list articles
Use singular with
:idfor a specific, viewable resource:GET /api/v1/players/:playerId– only in admin/special contextsGET /api/v1/leagues/:leagueIdGET /api/v1/contracts/:contractId
3. /me and my- for authenticated player data
/api/v1/merepresents the current authenticated player.Use it for self-scoped operations, without sending
playerId:GET /api/v1/me– current player profilePATCH /api/v1/me– update own profileGET /api/v1/me/teams– my teamsGET /api/v1/me/notifications– my notifications
For “my data inside something else” (e.g. inside a league), use the
my-prefix:GET /api/v1/leagues/:leagueId/my-teamGET /api/v1/leagues/:leagueId/my-contractsGET /api/v1/leagues/:leagueId/my-notifications
Rule of thumb: if the product wording is “my X”, the route should use
/meormy-and should not takeplayerIdfrom the client.
4. Path vs body
If an identifier is in the path, do not repeat it in the body:
- ✅
POST /api/v1/teams/:teamId/contractswith body{ articleId, startDate, duration, purchasePrice } - ❌ body also includes
teamIdorteamIDmirroring the path
- ✅
5. Authorization (backend)
“Hiding
playerIdfrom the URL” is not the security model; it’s just nicer API design.Real authorization rules:
- Resolve the authenticated player from session/JWT.
- Load the requested resource.
- Check ownership / league membership / role.
- If not allowed, return
403or404depending on how much you want to reveal.
6. Versioning
- The major version is a path segment, right after the surface it versions:
/api/v1/...for the SPA's API,/internal/v1/...for the scoring collector's. A route is added under the current version, never beside it. info.versioninbackend/openapi.yamlis the version of the contract, and its major must equal the segment:1.x.ydescribes/v1. An additive change, a new route or an optional field, bumps the minor.- A breaking change (a removed or renamed route or field, a narrower type, a new required input) moves to
/v2, and/v1stays mounted beside it until every client has moved. That is the point of versioning by path: the two can be served at once, by one Worker. /authis not versioned. It is the OAuth handshake, not a data contract, and its redirect URIs are registered with Google, so moving it would break sign-in on the next deploy for no client's benefit.- The API version is not the release version. A breaking API change is always a major release; a major release need not change the API. See Release Process.
Related
- OpenAPI Spec
- Release Process: how the release version relates to the API's
- Backend Architecture
- Backend Error Constants
