Understanding HTTP Methods and Routing
HTTP methods describe your intent and express the “what” of a request—what action you want to perform on a particular resource. This could be fetching data, adding data, updating data, or deleting data.
Routing expresses the “where” of a request—which resource you want to perform your action on. You need to tell the server where you want to go.
For example, when you send a GET request to /users, you’re saying: “I want to fetch some data” (the method) “from the users resource” (the route). The server takes both the method and the route, maps them to a particular handler or set of instructions, performs the necessary business logic and database operations, and returns the data.
Routing is essentially the mapping of URL parameters to server-side logic.
Static Routes
Static routes are routes without any variable parameters inside them. They remain consistent and constant. Examples:
GET /api/books- Fetches an array of booksPOST /api/books- Creates a new book resource
These routes never change. The string /api/books is always used when making the request, and it consistently returns the same type of data.
Important concept: The combination of method and route creates a unique path. GET /api/books and POST /api/books are two distinct endpoints that will never clash because the method differentiates them.
Dynamic Routes (Route Parameters/Path Parameters)
Dynamic routes contain variable parameters within the route path. Example:
GET /api/users/123
In this case, 123 represents the ID of a specific user. The application can fetch details of one particular user using the ID from the route parameter.
The server matches this pattern using a notation like:
GET /api/users/:id
The colon (:) convention indicates a dynamic parameter. This is an industry-wide practice across Java, Python, Node.js, Golang, and Rust. When a request comes in as /api/users/123, it gets routed to this handler because:
- The method matches (GET)
- The first part matches (
/api) - The second part matches (
/users) - The third part (123) gets inserted into the
:idslot
This provides human-readable routing: “Fetch me data from /api/users for the user with ID 123.”
These dynamic parameters are called route parameters or path parameters because they appear after the forward slash as part of the route itself.
Query Parameters
Query parameters are key-value pairs sent in the request, typically used with GET requests. Example:
GET /api/search?query=some+value
The structure consists of:
- The route:
/api/search - The query separator:
? - The key-value pair:
query=some+value
Why Query Parameters?
GET requests in REST APIs don’t have a body. While POST and PUT requests can send data in the request body, GET requests need an alternative way to send user-defined values to the server.
Path parameters serve a specific semantic purpose (identifying specific resources), but query parameters allow sending additional metadata about the request.
Practical Application: Pagination
Consider an endpoint that fetches a list of books:
GET /api/books
Response:
{
"data": [...array of books...],
"total": 100,
"currentPage": 1,
"totalPages": 5,
"limit": 20
}The server paginates the data, sending 20 books by default with metadata about the total. To fetch the next page:
GET /api/books?page=2
Common uses for query parameters:
- Pagination (page number, limit)
- Filtering (user-defined filters)
- Sorting (order, direction: ascending/descending)
All this information is sent as key-value pairs in query parameters.
Nested Routes
Nested routes result from nesting different types of resources to express semantic meaning. Example:
GET /api/users/123/posts/456
This can be understood at multiple levels:
/api/users- Static route returning all users/api/users/123- Returns information about user 123/api/users/123/posts- Returns all posts by user 123/api/users/123/posts/456- Returns post 456 by user 123
Each level expresses different semantic meaning:
- First level: Fetch data related to this user
- Second level: Fetch the posts of that user
- Third level: Fetch a particular post from that user
Each combination creates a unique route that the server matches to different handlers, resulting in different responses. This nesting allows for clear, readable API structures that express complex relationships between resources.
Route Versioning and Deprecation
Route versioning is a common practice in REST API servers to manage breaking changes and API evolution. Example:
GET /api/v1/products
GET /api/v2/products
Version 1 Response:
{
"data": [
{"id": 1, "name": "Product A", "price": 100}
]
}Version 2 Response:
{
"data": [
{"id": 1, "title": "Product A", "price": 100}
]
}Notice the field changed from name to title.
Benefits of Versioning
- Clear intent: Explicitly shows which version of the API is being used
- No route changes needed: Instead of creating
/api/new-products, you simply increment the version - Graceful migration: Frontend engineers receive notice that v1 is deprecated and have a window to migrate to v2
- Stable workflow: Provides a complete workflow for adding breaking changes to API endpoints
The typical process: Release v2, deprecate v1, allow a migration window, eventually remove v1 and potentially rename v2 to v1 for the next cycle.
Catch-All Route
The catch-all route handles requests to endpoints that don’t exist on the server. Example request:
GET /api/v3/products
If the server doesn’t serve this route, after going through all route matching algorithms, the request reaches the catch-all handler:
* (or wildcard pattern)
Instead of sending a null response (the default behavior), the catch-all route sends a user-friendly message indicating that the requested route does not exist or was not found.
Summary
Understanding these routing concepts is essential for working with backend codebases:
- Static routes for consistent endpoints
- Dynamic routes with path parameters for resource identification
- Query parameters for metadata and filtering
- Nested routes for expressing resource relationships
- Versioning for managing API evolution
- Catch-all routes for handling non-existent endpoints
These concepts are fundamental to REST API design and are implemented across all major backend frameworks and languages.