URL encoding for REST APIs
REST APIs put data in URLs in three places: path segments, query parameters, and (sometimes) URL-encoded request bodies. Each has different encoding requirements, and getting them right is the difference between a working integration and a debugging session.
This article covers the three contexts, common framework behaviors, and the edge cases that trip up real-world REST clients.
The three URL contexts in a REST API
1. Path segments — /users/{id}/orders/{orderId}
The {id} and {orderId} need URL encoding when they contain anything beyond letters and digits. Use RFC 3986 strict (space → %20).
2. Query parameters — ?q=value&page=2
Each value needs encoding. Most APIs accept both form-encoded (+ for space) and strict (%20) — but strict is safer.
3. Form-encoded request body — name=John&message=Hello
Same encoding as query parameters, but in the request body with Content-Type: application/x-www-form-urlencoded.
Path segment encoding
The most error-prone of the three. Path segments must encode:
- Spaces (as
%20— never+) - Forward slashes within data (as
%2F) - Any reserved character used as data
- All non-ASCII characters (as UTF-8 percent-encoded bytes)
// User ID is a UUID
GET /users/550e8400-e29b-41d4-a716-446655440000 ← fine, no encoding needed
// User ID has a slash (unusual but possible)
GET /users/A%2FB ← encoded
// Decoded interpretation: user ID is literally "A/B"
The %2F-in-path landmine
Many servers reject %2F in path components by default. The default Apache configuration treats encoded slashes as a path-traversal attack and returns 404 or 400.
Workaround on Apache: Set AllowEncodedSlashes On in the server config.
Workaround on Nginx: Custom location matching with regex (no clean built-in option).
Best practice: Avoid putting data with potential / characters in path segments. Use a query parameter instead, where encoded slashes are universally accepted.
Query parameter encoding for filters and search
The common REST pattern of ?filter=value&sort=name:
// Simple values
GET /products?q=laptop&category=electronics
// With special chars
GET /products?q=rock%20%26%20roll&category=music
// Decoded: q="rock & roll", category="music"
If you don’t encode the & in rock & roll, the parser sees:
?q=rock
&roll= ← interpreted as separate parameter with empty value
&category=music
Always encode each value before concatenating.
API-specific conventions
GitHub API: strict, returns 400 on bad encoding
// Search repositories
GET /search/repositories?q=hello+world+language:python
// + as space works
// Special chars in query: must be percent-encoded
GET /search/repositories?q=%2Bhello%20%22world%22
Stripe API: form-encoded bodies
POST /v1/customers
Content-Type: application/x-www-form-urlencoded
name=Jenny%20Rosen&email=jenny%40example.com
Stripe’s POST endpoints accept form-encoded bodies, not JSON. The encoding is standard URL encoding.
AWS API Gateway: strict path encoding
AWS expects RFC 3986 strict for path segments. Spaces must be %20, not +. Hex must be uppercase.
OpenStreetMap Overpass API: complex query encoding
The Overpass API takes its own query language as a URL parameter. The whole query must be URL-encoded, including special characters that are syntax in the query language itself.
Building REST API URLs in real code
Node.js
const url = new URL('https://api.example.com/users/' + encodeURIComponent(userId));
url.searchParams.set('include', 'orders,profile');
url.searchParams.set('limit', '50');
fetch(url.toString());
Python (requests library)
import requests
from urllib.parse import quote
response = requests.get(
f'https://api.example.com/users/{quote(user_id, safe="")}',
params={'include': 'orders,profile', 'limit': 50}
)
# requests auto-encodes params dict
cURL
# GET with query params
curl --data-urlencode "q=hello world" \
--data-urlencode "filter=type:premium" \
-G https://api.example.com/search
# POST with form-encoded body
curl -X POST https://api.example.com/users \
--data-urlencode "name=Jenny Rosen" \
--data-urlencode "email=jenny@example.com"
Embedding URLs as parameter values
Webhook URLs, OAuth callbacks, and redirect parameters often contain entire URLs as values. The inner URL must be fully URL-encoded:
// Setting up an OAuth callback
const callbackUrl = 'https://myapp.com/auth/callback?ref=oauth_v2';
const authUrl = `https://accounts.example.com/authorize?redirect_uri=${encodeURIComponent(callbackUrl)}&client_id=abc123`;
// → ?redirect_uri=https%3A%2F%2Fmyapp.com%2Fauth%2Fcallback%3Fref%3Doauth_v2&client_id=abc123
The inner URL’s :, /, ?, & all need encoding so the outer URL parser doesn’t misinterpret them.
Common REST encoding mistakes
1. Encoding the entire URL instead of just values
// Wrong
const url = encodeURIComponent('https://api.example.com/users?id=123');
// "https%3A%2F%2Fapi.example.com%2Fusers%3Fid%3D123"
// → No longer a URL
2. Mixing path and query encoding styles
// Wrong: + in a path means literal +
const userId = encodeURIComponent('John Doe').replace(/%20/g, '+');
GET /users/John+Doe // → looking for user named "John+Doe" literally
3. Forgetting to encode commas in arrays
// Some APIs use commas as multi-value separator
GET /search?fields=id,name,email ← if the field names are guaranteed clean, fine
// But user-provided values must encode commas
GET /search?names=Smith%2C+John&Jones%2C+Mary
// "Smith, John" + "Jones, Mary" — without encoded commas, server sees four names
4. Sending JSON values without proper escaping
Some APIs accept JSON-encoded values in URL parameters. The JSON itself must be properly escaped before URL-encoding:
const filter = { status: "active", tier: "premium" };
const jsonStr = JSON.stringify(filter);
// '{"status":"active","tier":"premium"}'
const param = encodeURIComponent(jsonStr);
// "%7B%22status%22%3A%22active%22%2C%22tier%22%3A%22premium%22%7D"
const url = `/search?filter=${param}`;
Debugging a REST API encoding issue
Step 1: Capture the actual HTTP request. Use browser DevTools, Postman, or curl -v. Note the exact path and query string sent.
Step 2: Decode the URL. Paste it into our URL decoder and check if the decoded form matches what you intended.
Step 3: Check the server’s docs for encoding conventions. Some APIs explicitly require uppercase hex (%2C not %2c), some require strict path encoding (no + for space).
Step 4: Re-encode with the right tool. If you’re working in JavaScript, prefer the URL constructor and URLSearchParams over manual concatenation — they handle the edge cases.
Bottom line
Three rules cover most cases:
- Encode each value separately, never the whole URL.
- Use
%20for spaces in path segments; either%20or+for query strings is fine. - Use your language’s standard library (
URL+URLSearchParamsin JS,urllib.parsein Python, etc.) instead of manual string concatenation.
Found this useful? Try the URL decoder, the URL encoder, or browse all tools.