Skip to content

URL Design

URLs are a human-readable interface — they communicate structure, help users navigate, and set expectations.

A good URL should be guessable: if you know /companies/42/employees exists, you can intuit /companies/42/invoices without reading docs (IDs aside). Good URLs organise knowledge into a hierarchy of resources.

They also matter for machines: search engines, API clients, OpenAPI tooling, caching layers, and AI agents all benefit from predictable, consistent paths. An agent navigating an API can infer resource relationships from URL structure alone — no docs lookup needed. A well-designed URL scheme makes the API self-documenting.

Current status

These conventions are enforced on eu-tools via a runtime check. They are the target for all backends, but there is no current plan to migrate existing routes.

Hyphens over underscores

Use hyphens (-) to separate words in URL segments, not underscores (_).

This follows Google's URL structure guidelines ⧉ and is the dominant convention in web APIs.

A runtime check ([validate_hyphenated_routes][shared.helpers.validate_routes.validate_hyphenated_routes]) runs on opted-in apps in development mode and raises on any violation. Path parameters (e.g. <uuid:id>) are ignored — only static segments are checked.

RESTful naming

Nouns, not verbs

URL segments should name resources (nouns). The HTTP method expresses the action.

Method Meaning
GET Read
POST Create
PUT / PATCH Update
DELETE Remove

Plural nouns for collections

Use plural nouns for collection endpoints.

Sub-resources for relationships

Nest related resources under their parent.

Examples

Good Bad Why
POST /jobs/<id>/failures POST /jobs/enqueue-failing-job Noun-based, method = action
GET /cache/keys GET /cache/count-keys-and-space Resource, not operation
GET /alaners/<id>/coffee-profiles GET /alaners/<id>/get-coffee-profile Plural, no verb
GET /companies/<id>/employees GET /get-employees-for-company Sub-resource hierarchy
POST /members/<id>/claims POST /create-claim-for-member HTTP method = create

Renaming a route safely

Our APIs are consumed by both the web app and the mobile app. The web app is always up-to-date on deploy, but mobile clients may run older versions for weeks. Renaming a route therefore requires a transition period.

  1. Add the new route alongside the old one — both should point to the same handler (or the old one redirects to the new one).
  2. Update the web app to call the new route.
  3. Update the mobile app to call the new route, and wait for adoption — the old route must stay alive until the minimum supported mobile version uses the new one.
  4. Remove the old route once no active client relies on it.

Warning

Never rename a route in-place in a single deploy — mobile users on older versions will get 404s.

Exceptions

Existing routes don't need to be renamed unless they are already being modified.

Source