6.4. Query Parameters
Table of Contents
Understanding Query Parameters
When you build web backends, query parameters are one of the most common ways that clients send extra information with a request. You will see them everywhere, for example when searching, filtering, sorting, or paginating data.
This chapter focuses on what query parameters are, how they differ from other types of parameters, and how to use them correctly, with many concrete examples.
What Are Query Parameters?
A query parameter is a key value pair that appears in the URL after a question mark ?.
Basic structure:
https://example.com/search?query=python&limit=10Breakdown:
https://example.comis the scheme and domain./searchis the path.?starts the query string.query=pythonis a query parameter.limit=10is another query parameter.&separates multiple query parameters.
In general, a URL with query parameters looks like this:
/path?key1=value1&key2=value2&key3=value3
Each key=value pair is one query parameter.
Rule: Query parameters always appear after ? in the URL and are separated by &.
Rule: Query parameters are not part of the path. They are optional and can appear in any order.
Query Parameters vs Path Parameters
You have already seen path parameters in routing. Path parameters are part of the path itself, for example:
/users/123
Here 123 might be a path parameter that identifies a specific user.
Query parameters are not part of the path, but are attached after ?:
/users?active=true&limit=20Conceptual difference
- Path parameters identify a specific resource or a specific location.
Example:/users/123usually means user with id123. - Query parameters modify or filter how a resource is returned.
Example:/users?active=truemeans: give me users, but only active ones.
You can combine both:
/users/123/orders?status=delivered&limit=10Here:
- Path part:
/users/123/orders - user id is
123 - Query part:
?status=delivered&limit=10 - status filter is
delivered - limit is
10items
A useful mental rule:
Rule: Use path parameters to say which resource.
Use query parameters to say how you want it.
Common Uses of Query Parameters
Query parameters are typically used for:
- Filtering
- Example:
/products?category=books&price_max=20- Returns products in category "books" with price less than or equal to 20.
- Sorting
- Example:
/products?sort=price_asc- Returns products sorted by price ascending.
- Pagination
- Example:
/products?page=2&page_size=50- Returns page 2 of products, 50 items per page.
- Searching
- Example:
/search?query=laptop&in_stock=true- Optional flags
- Example:
/users/123?include=orders,profileUsing query parameters for these things keeps your path clean and shows clearly that these are optional modifiers, not the main resource identifier.
Anatomy of a Query String
Consider this URL:
https://api.example.com/articles?author=alice&tag=python&tag=web&sort=recent&page=3Break it into a table:
| Part | Example | Meaning |
|---|---|---|
| Path | /articles | Main resource |
author | author=alice | Filter by author |
tag (1) | tag=python | One tag filter |
tag (2) | tag=web | Another tag filter |
sort | sort=recent | Sorting option |
page | page=3 | Pagination page |
Important details:
- A key can appear multiple times (
tag=python&tag=web). - Order of parameters usually does not matter.
- Keys and values are strings, and are URL encoded.
URL Encoding Basics
URLs can only safely include certain characters. Others must be encoded.
For example, a space is not allowed directly in the query. It is encoded as + or %20.
Examples:
| Original value | Encoded in URL |
|---|---|
python backend | python+backend |
fast api | fast+api |
C# | C%23 |
a&b | a%26b |
So a search query like:
/search?query=python backendactually looks like:
/search?query=python+backendYour web framework and HTTP libraries usually handle this encoding and decoding for you. When you read the query parameter in code, you get back the decoded value.
Required vs Optional Query Parameters
By default, query parameters are optional. A client can decide whether to send them or not.
For example, suppose you design this endpoint:
GET /products?category=booksThe client might call:
/products?category=books/products(no query parameters)
You need to decide what your backend will do when the parameter is missing:
- Use a default value.
- Return all data.
- Return an error.
Example: optional parameters with defaults
GET /products?category=books&limit=20You could define:
categoryis optional, default is "all categories".limitis optional, default is 10.
So:
/products?category=books&limit=20
returns 20 book products./products?category=books
uses defaultlimit=10./products
uses defaultcategory=all,limit=10.
You must document these defaults in your API description.
Example: required query parameters
Sometimes, you intentionally make a query parameter required, for example:
GET /search?query=pythonYou might decide:
queryis required.- If
queryis missing, return an error response.
So:
/search?query=pythonis valid./searchreturns a 400 Bad Request.
Multiple Values for the Same Parameter
Clients can send the same query parameter key multiple times. How your backend framework exposes this depends on the framework.
Example URL:
/articles?tag=python&tag=web&tag=backendPossible interpretations:
- The backend might treat
tagas a list of values:["python", "web", "backend"]. - Or if you only read the first value, you might only see
"python".
As an API designer, you should choose a clear style and document it. Some options:
- Allow repeated keys:
/articles?tag=python&tag=web- Allow comma separated values:
/articles?tag=python,web
Both are common. Your backend code must handle whichever style you choose.
Table of common patterns:
| Client URL style | Backend sees as |
|---|---|
?tag=python&tag=web | ["python", "web"] |
?tag=python,web | "python,web" then split it |
?tag[]=python&tag[]=web | ["python", "web"] |
You do not have to support every style. Pick one and be consistent.
Designing Query Parameters
When you design query parameters, think about clarity and predictability.
Naming conventions
Use clear, descriptive names:
page,page_sizeorlimit,offsetsort,order_byprice_min,price_maxcreated_after,created_beforeinclude,fields
Avoid cryptic names like p, s, or q2.
Boolean parameters
Boolean query parameters often appear as:
?active=true?active=false
Sometimes developers shorten this, for example:
?activeto meantrue- nothing to mean
false
That can be confusing. Prefer explicit values.
Sorting
Several patterns are common for sorting:
- Single parameter with pattern:
/users?sort=name_asc
/users?sort=name_desc
/users?sort=-name (minus sign for descending)- Separate field and direction:
/users?sort_by=name&sort_dir=ascChoose one style and apply it everywhere in your API.
Pagination
Pagination is nearly always done with query parameters. Common patterns:
| Pattern | Example | Meaning |
|---|---|---|
| page / page_size | ?page=2&page_size=50 | Page number and items per page |
| limit / offset | ?limit=50&offset=100 | Page size and offset from start |
| cursor based | ?cursor=abc123&limit=50 | Use a cursor token, not a numeric page index |
You do not need cursor based pagination for beginners. Page / page_size is simple and widely used.
Query Parameters and the HTTP Method
You can technically use query parameters with any HTTP method, for example:
GET /products?category=booksPOST /products?dry_run=trueDELETE /products/123?force=true
However, the most common use is with GET:
- In
GETrequests, the query parameters specify filters and options for reading data.
For example:
GET /users?country=US&active=true
In requests that modify data (POST, PUT, PATCH, DELETE), you usually put most of the input in the request body, and use query parameters only for control flags, such as:
POST /orders?send_email=trueHere:
- The order data is in the body (JSON or form).
- The
send_emailflag is in the query.
This separation keeps URLs readable and makes clear what is core data and what is optional behavior.
Query Parameters vs Request Body
For a beginner, it is useful to compare query parameters with request bodies.
| Feature | Query Parameters | Request Body |
|---|---|---|
| Location | In the URL after ? | In the HTTP message body |
| Common use | Filters, options, pagination | Main data for create/update |
| Typical methods | Mostly GET | POST, PUT, PATCH |
| Data format | Simple key value pairs (strings) | JSON, form data, XML, etc. |
| Size limit | Often limited by URL length | Usually can be larger |
Example:
GET /products?category=books&limit=10Here:
- No body is needed.
- Category and limit are query parameters.
Another example:
POST /products
Content-Type: application/json
{
"name": "Clean Code",
"category": "books",
"price": 25.00
}Here:
- The product data is in the body.
- You could still add query parameters as flags, such as
?notify_subscribers=true.
Examples of Query Parameter Usage
Simple filtering
GET /users?country=DEBehavior:
- Return users whose
countryis"DE".
Multiple filters
GET /users?country=DE&active=true&role=adminBehavior:
- Return users with all of:
country = "DE"active = truerole = "admin"
Optional search
GET /articles?query=python
GET /articlesBehavior:
- First request: filter by search query
"python". - Second request: no search filter, maybe return all articles.
Pagination example
GET /articles?page=3&page_size=20Backend logic, for example:
page_sizedefault is 20.- Starting index is:
$$\text{offset} = (\text{page} - 1) \times \text{page\_size}$$
So:
page = 3,page_size = 20offset = (3 - 1) × 20 = 40
The backend might run a query like:
- "Get 20 articles starting from index 40."
Formula: For page based pagination,
$$\text{offset} = (\text{page} - 1) \times \text{page\_size}$$
Sorting example
GET /products?sort=price_asc
GET /products?sort=-created_atBackend interpretation:
- First: order by
priceascending. - Second: order by
created_atdescending (minus sign indicates descending).
Multiple tags example
Option 1: repeated parameters:
GET /articles?tag=python&tag=backendOption 2: comma separated:
GET /articles?tag=python,backendBackend must convert these into a list internally, such as:
["python", "backend"]Handling Query Parameters in Code (Conceptually)
Different web frameworks and languages have different syntax, but the ideas are the same.
Almost always, you:
- Read the query parameters from the request.
- Validate them (type check, ranges, allowed values).
- Apply them to your logic (filters, pagination, sorting).
- Provide defaults when a parameter is missing.
Conceptual pseudocode:
def list_products(request):
category = request.query.get("category") # str or None
page = int(request.query.get("page", 1)) # default 1
page_size = int(request.query.get("page_size", 20)) # default 20
# Validate page_size
if page_size > 100:
page_size = 100 # or return an error
# Calculate offset
offset = (page - 1) * page_size
# Use these values to query the database
products = find_products(category=category, offset=offset, limit=page_size)
return productsYou do not need to know Python details here. The key steps apply in any backend language or framework.
Good Practices for Query Parameters
To finish, here are some practical guidelines.
Be consistent
Use the same parameter names and patterns across your whole API.
- If you use
pageandpage_sizein one place, do not usepandlimitin another. - If you use
sort=-fieldfor descending, use that everywhere.
Prefer simple types
Keep query parameters simple:
- Strings
- Numbers
- Booleans
Avoid complex JSON structures in the query string, such as:
?filter={"price":{"min":10,"max":50}}This is hard to read, hard to encode, and often better handled in the request body if you really need complex filters.
Validate everything
Do not blindly trust any query parameter:
- Check that numbers are within allowed ranges.
- Example:
page >= 1,1 <= page_size <= 100. - Check that sort fields are allowed.
- Example: only
name,price,created_atare valid. - Check that values are of the correct type.
If something is wrong, return a clear error response with a helpful message.
Document your parameters
For each endpoint, document:
- Which query parameters exist.
- Their types.
- Whether they are required or optional.
- Default values.
- Allowed ranges or values.
This will later be expressed more formally with tools like OpenAPI and Swagger, but the idea is the same.
You now know what query parameters are, how they differ from path parameters and request bodies, and how they are commonly used for filtering, sorting, searching, and pagination. In the next topics, you will see how to work with other request parts, such as request bodies and form data, in more detail.
Views: 8
KAHIBARO