API Reference
This document provides comprehensive API reference for integrating URL encoding/decoding functionality into your applications, including JavaScript examples and implementation details.
JavaScript API
Core Functions
encodeURIComponent(string)
Standard JavaScript function for URL encoding:
// Basic encoding
const encoded = encodeURIComponent('Hello World!');
console.log(encoded); // "Hello%20World%21"
// Special characters
const special = encodeURIComponent('user@example.com');
console.log(special); // "user%40example.com"
// Unicode support
const unicode = encodeURIComponent('こんにちは');
console.log(unicode); // "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF"
decodeURIComponent(string)
Standard JavaScript function for URL decoding:
// Basic decoding
const decoded = decodeURIComponent('Hello%20World%21');
console.log(decoded); // "Hello World!"
// Special characters
const email = decodeURIComponent('user%40example.com');
console.log(email); // "user@example.com"
// Unicode decoding
const japanese = decodeURIComponent('%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF');
console.log(japanese); // "こんにちは"
Enhanced URL Encoder Class
Custom implementation with additional features:
class URLEncoder {
/**
* Encode text with custom options
* @param {string} text - Text to encode
* @param {Object} options - Encoding options
* @returns {string} Encoded text
*/
static encode(text, options = {}) {
const { spaceAsPlus = false, customReserved = [], preserveCase = false } = options;
let encoded = encodeURIComponent(text);
// Replace %20 with + if requested
if (spaceAsPlus) {
encoded = encoded.replace(/%20/g, '+');
}
// Handle custom reserved characters
customReserved.forEach((char) => {
const encodedChar = encodeURIComponent(char);
encoded = encoded.replace(new RegExp(encodedChar, 'g'), char);
});
// Preserve case for hex digits
if (!preserveCase) {
encoded = encoded.toUpperCase();
}
return encoded;
}
/**
* Decode URL-encoded text with error handling
* @param {string} text - Text to decode
* @param {Object} options - Decoding options
* @returns {Object} Result object with success/error info
*/
static decode(text, options = {}) {
const { strictMode = true } = options;
try {
// Handle + as space
const normalized = text.replace(/\+/g, '%20');
const decoded = decodeURIComponent(normalized);
return {
success: true,
result: decoded,
error: null,
};
} catch (error) {
if (strictMode) {
return {
success: false,
result: null,
error: `Decoding failed: ${error.message}`,
};
} else {
// Attempt partial decoding
return this.partialDecode(text);
}
}
}
/**
* Attempt partial decoding for malformed input
* @param {string} text - Malformed text
* @returns {Object} Partial decode result
*/
static partialDecode(text) {
const chunks = text.split('%');
let result = chunks[0];
for (let i = 1; i < chunks.length; i++) {
const chunk = chunks[i];
if (chunk.length >= 2) {
const hex = chunk.substring(0, 2);
const rest = chunk.substring(2);
try {
const charCode = parseInt(hex, 16);
result += String.fromCharCode(charCode) + rest;
} catch {
result += '%' + chunk;
}
} else {
result += '%' + chunk;
}
}
return {
success: true,
result: result,
error: 'Partial decoding applied',
};
}
/**
* Validate URL encoding
* @param {string} text - Text to validate
* @returns {Object} Validation result
*/
static validate(text) {
const issues = [];
// Check for malformed percent encoding
const percentPattern = /%[0-9A-Fa-f]{2}/g;
const invalidPercent = /%(?![0-9A-Fa-f]{2})/g;
if (invalidPercent.test(text)) {
issues.push('Invalid percent encoding found');
}
// Check for unencoded reserved characters
const unencodedReserved = /[<>"{}|\\^`\[\]]/g;
if (unencodedReserved.test(text)) {
issues.push('Unencoded reserved characters found');
}
// Check for control characters
const controlChars = /[\x00-\x1F\x7F]/g;
if (controlChars.test(text)) {
issues.push('Control characters detected');
}
return {
isValid: issues.length === 0,
issues: issues,
};
}
}
Batch Processing API
class BatchURLProcessor {
/**
* Process multiple URLs in batch
* @param {string[]} urls - Array of URLs to process
* @param {string} operation - 'encode' or 'decode'
* @param {Object} options - Processing options
* @returns {Promise<Object[]>} Array of results
*/
static async processBatch(urls, operation, options = {}) {
const { chunkSize = 100, onProgress = null, errorHandling = 'continue' } = options;
const results = [];
const totalUrls = urls.length;
for (let i = 0; i < totalUrls; i += chunkSize) {
const chunk = urls.slice(i, i + chunkSize);
const chunkResults = chunk.map((url, index) => {
try {
const result = operation === 'encode' ? URLEncoder.encode(url) : URLEncoder.decode(url);
return {
index: i + index,
input: url,
output: result.result || result,
success: result.success !== false,
error: result.error || null,
};
} catch (error) {
if (errorHandling === 'stop') {
throw error;
}
return {
index: i + index,
input: url,
output: null,
success: false,
error: error.message,
};
}
});
results.push(...chunkResults);
// Report progress
if (onProgress) {
onProgress({
processed: results.length,
total: totalUrls,
percentage: Math.round((results.length / totalUrls) * 100),
});
}
// Yield control to prevent blocking
await new Promise((resolve) => setTimeout(resolve, 0));
}
return results;
}
}
Query String Utilities
Query Parameter Encoding
class QueryStringUtils {
/**
* Build encoded query string from object
* @param {Object} params - Parameters object
* @param {Object} options - Encoding options
* @returns {string} Encoded query string
*/
static build(params, options = {}) {
const { arrayFormat = 'brackets', spaceAsPlus = false } = options;
const pairs = [];
Object.entries(params).forEach(([key, value]) => {
if (Array.isArray(value)) {
value.forEach((item) => {
const encodedKey =
arrayFormat === 'brackets' ? `${encodeURIComponent(key)}[]` : encodeURIComponent(key);
const encodedValue = encodeURIComponent(item);
pairs.push(`${encodedKey}=${encodedValue}`);
});
} else if (value !== null && value !== undefined) {
const encodedKey = encodeURIComponent(key);
const encodedValue = encodeURIComponent(value);
pairs.push(`${encodedKey}=${encodedValue}`);
}
});
let queryString = pairs.join('&');
if (spaceAsPlus) {
queryString = queryString.replace(/%20/g, '+');
}
return queryString;
}
/**
* Parse encoded query string to object
* @param {string} queryString - Query string to parse
* @param {Object} options - Parsing options
* @returns {Object} Parsed parameters
*/
static parse(queryString, options = {}) {
const { arrayFormat = 'brackets' } = options;
const params = {};
// Remove leading ? if present
const cleanQuery = queryString.replace(/^\?/, '');
if (!cleanQuery) return params;
const pairs = cleanQuery.split('&');
pairs.forEach((pair) => {
const [key, value = ''] = pair.split('=');
const decodedKey = decodeURIComponent(key.replace(/\+/g, ' '));
const decodedValue = decodeURIComponent(value.replace(/\+/g, ' '));
if (arrayFormat === 'brackets' && decodedKey.endsWith('[]')) {
const arrayKey = decodedKey.slice(0, -2);
if (!params[arrayKey]) params[arrayKey] = [];
params[arrayKey].push(decodedValue);
} else {
if (params[decodedKey]) {
// Convert to array if multiple values
if (!Array.isArray(params[decodedKey])) {
params[decodedKey] = [params[decodedKey]];
}
params[decodedKey].push(decodedValue);
} else {
params[decodedKey] = decodedValue;
}
}
});
return params;
}
}
Error Handling
Error Types
class URLEncodingError extends Error {
constructor(message, code, originalText) {
super(message);
this.name = 'URLEncodingError';
this.code = code;
this.originalText = originalText;
}
}
// Error codes
const ERROR_CODES = {
INVALID_INPUT: 'INVALID_INPUT',
MALFORMED_ENCODING: 'MALFORMED_ENCODING',
UNICODE_ERROR: 'UNICODE_ERROR',
SIZE_LIMIT_EXCEEDED: 'SIZE_LIMIT_EXCEEDED',
};
Safe Encoding Wrapper
function safeEncode(text, options = {}) {
try {
if (typeof text !== 'string') {
throw new URLEncodingError('Input must be a string', ERROR_CODES.INVALID_INPUT, text);
}
if (text.length > (options.maxLength || 10000)) {
throw new URLEncodingError(
'Input exceeds maximum length',
ERROR_CODES.SIZE_LIMIT_EXCEEDED,
text,
);
}
return {
success: true,
result: URLEncoder.encode(text, options),
error: null,
};
} catch (error) {
return {
success: false,
result: null,
error: error.message,
};
}
}
Browser Compatibility
Feature Detection
function checkURLEncodingSupport() {
const features = {
encodeURIComponent: typeof encodeURIComponent === 'function',
decodeURIComponent: typeof decodeURIComponent === 'function',
unicode: true,
performance: typeof performance !== 'undefined',
};
// Test Unicode support
try {
const test = encodeURIComponent('🌟');
features.unicode = test === '%F0%9F%8C%9F';
} catch {
features.unicode = false;
}
return features;
}
Polyfills
// Polyfill for older browsers
if (!window.encodeURIComponent) {
window.encodeURIComponent = function (str) {
return escape(str).replace(/\+/g, '%2B');
};
}
if (!window.decodeURIComponent) {
window.decodeURIComponent = function (str) {
return unescape(str.replace(/\+/g, ' '));
};
}
Usage Examples
Real-world Integration
// Express.js middleware example
function urlEncodingMiddleware(req, res, next) {
req.safeQuery = {};
Object.entries(req.query).forEach(([key, value]) => {
try {
req.safeQuery[key] = decodeURIComponent(value);
} catch (error) {
req.safeQuery[key] = value; // Keep original if decode fails
}
});
next();
}
// React component example
function URLInput({ onEncode, onDecode }) {
const [input, setInput] = useState('');
const [output, setOutput] = useState('');
const handleEncode = () => {
const result = safeEncode(input);
if (result.success) {
setOutput(result.result);
onEncode?.(result.result);
} else {
console.error('Encoding failed:', result.error);
}
};
const handleDecode = () => {
const result = URLEncoder.decode(input);
if (result.success) {
setOutput(result.result);
onDecode?.(result.result);
} else {
console.error('Decoding failed:', result.error);
}
};
return (
<div>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Enter text to encode/decode"
/>
<button onClick={handleEncode}>Encode</button>
<button onClick={handleDecode}>Decode</button>
<textarea value={output} readOnly placeholder="Result will appear here" />
</div>
);
}
This API reference provides comprehensive guidance for implementing URL encoding/decoding functionality in various JavaScript environments and frameworks.