API Development

URL Encoding Best Practices for API Development

2026-03-13 ~10 min read API, Query String, REST

Why API Developers Need to Understand URL Encoding

In RESTful API development, URL encoding is a step that appears simple but is often done incorrectly. Improper URL encoding handling can lead to: parameter values being truncated, data parsing failures, double-encoding resulting in garbled text, SQL injection risk, and cross-language API integration issues.

This article provides systematic, code-driven guidance on the correct practices for URL encoding in API development.

Correct Handling of Query Strings

The query string is the part of a URL after the ?, in the format key=value&key2=value2. Each key and value must be URL-encoded separately.

Common Mistake: String Concatenation
const url = '/api/search?q=' + userInput;
If userInput contains &, =, #, or other characters, the URL structure will be broken.

Correct Approach: Use encodeURIComponent or URLSearchParams
const url = '/api/search?q=' + encodeURIComponent(userInput);
Or use the URLSearchParams API (preferred).

JavaScript / TypeScript (Frontend & Node.js)

// Method 1: URLSearchParams (recommended)
const params = new URLSearchParams({
  q: 'New York coffee shops',
  category: 'food&drink',
  page: '1'
});
const url = `/api/search?${params.toString()}`;
// → /api/search?q=New+York+coffee+shops&category=food%26drink&page=1

// Method 2: Manually encode each parameter value
const url2 = `/api/search?q=${encodeURIComponent('New York coffee shops')}&category=${encodeURIComponent('food&drink')}`;

// Parsing URL parameters (backend / Node.js)
const { URL } = require('url');
const reqUrl = new URL(req.url, 'http://localhost');
const q = reqUrl.searchParams.get('q');
// Automatically decoded, directly gives 'New York coffee shops'

Python (requests library)

import requests

# The requests library handles URL encoding automatically
response = requests.get(
    'https://api.example.com/search',
    params={
        'q': 'New York coffee shops',
        'category': 'food&drink',
        'page': 1
    }
)
# Actual request: /search?q=New+York+coffee+shops&category=food%26drink&page=1

# Flask backend receiving (auto-decoded)
from flask import request
q = request.args.get('q')  # → 'New York coffee shops' (already decoded)

PHP

<?php
// Build query string
$params = http_build_query([
    'q' => 'New York coffee shops',
    'category' => 'food&drink',
    'page' => 1
]);
$url = "https://api.example.com/search?" . $params;
// → https://api.example.com/search?q=New+York+coffee+shops&category=food%26drink&...

// Receiving ($\_GET auto-decodes)
$q = $_GET['q']; // → 'New York coffee shops'
?>

Java (Spring Boot)

// Sending a request (using UriComponentsBuilder)
UriComponents uriComponents = UriComponentsBuilder
    .fromUriString("https://api.example.com/search")
    .queryParam("q", "New York coffee shops")
    .queryParam("category", "food&drink")
    .build()
    .encode();  // Encodes automatically

// Spring MVC receiving
@GetMapping("/search")
public ResponseEntity<?> search(@RequestParam String q) {
    // q is already decoded, use it directly
    return ResponseEntity.ok(searchService.search(q));
}

Double Encoding Problem

Double encoding is the most common URL encoding bug in API development. It occurs when a component encodes an already-encoded string a second time:

// Wrong: double encoding
const value = 'hello world';
const encoded = encodeURIComponent(value); // → 'hello%20world'
const doubleEncoded = encodeURIComponent(encoded); // → 'hello%2520world'
// % itself is encoded as %25 — the server decodes once and still gets garbage!

// Correct: only encode the raw value once
const url = `/api/greet?name=${encodeURIComponent('hello world')}`;
// → /api/greet?name=hello%20world

Common Double Encoding Scenarios
• The backend receives a parameter and places it directly into another HTTP request's URL without decoding it first.
• nginx / Apache URL rewrite rules have already encoded the URL, but the application layer encodes it again.
• Using axios's params option while also manually calling encodeURIComponent on the values.

URL Encoding Method Selection Guide

ScenarioRecommended MethodNotes
Query string parameter value encodeURIComponent() Strictest — encodes &, =, + as well
Complete URL encodeURI() Preserves URL structural characters
Building multiple parameters URLSearchParams Automatically encodes all parameters
HTML form data Browser handles automatically Space encoded as +, others as %XX
axios params option Pass object directly axios encodes automatically — do not double-encode
Python requests params Pass dict directly requests encodes automatically

Encoding Spaces: %20 vs +

Spaces can be encoded in two ways, each with a different context:

Modern APIs should standardize on %20 (encodeURIComponent) to avoid ambiguity around how + is interpreted in different contexts. If you must support HTML form encoding, verify how your backend decodes it.

Axios URL Encoding Behavior

import axios from 'axios';

// Correct: use a params object — axios encodes automatically
axios.get('/api/search', {
  params: {
    q: 'New York coffee shops',
    category: 'food&drink'
  }
});
// Actual request: /api/search?q=New%20York%20coffee%20shops&category=food%26drink

// Wrong: manual encoding + params (double encoding)
axios.get('/api/search', {
  params: {
    q: encodeURIComponent('New York coffee shops')  // already encoded; axios encodes again!
  }
});

When Backends Should Decode

Most modern frameworks (Express, Spring, Django, Laravel) automatically decode route parameters and query strings when parsing them. Developers do not need to manually call a decode function.

Do not manually decode in frameworks that auto-decode
If the framework already decoded the value, calling decodeURIComponent(req.query.q) again may throw an error (URIError: malformed URI sequence) when the original value contains a literal % character.

Verify Your URL Encoding Results

Use our free tool to test URL encoding in real time and ensure your API parameters are correct.

Go to the Tool