JSON to Query String

What is a Query String?

A Query String is a part of a URL that contains data in key-value pairs, typically used to pass parameters to web servers. It starts with a question mark (?) and uses ampersands (&) to separate multiple parameters.

Format: ?key1=value1&key2=value2&key3=value3

Example: https://api.example.com/users?name=John&age=30&active=true

Understanding the Conversion

Converting JSON to Query String transforms structured data objects into flat URL parameters. This is essential for GET requests, search filters, pagination, and many web APIs that expect parameters in the URL.

JSON vs Query String

AspectJSONQuery String
StructureHierarchical, nested objectsFlat key-value pairs
Data TypesMultiple types (string, number, boolean, array, object, null)All values are strings
UsageData storage, APIs, configurationURL parameters, GET requests
Format{"name": "John", "age": 30}name=John&age=30
EncodingUTF-8 stringsURL-encoded strings

Why Convert JSON to Query String?

1. GET Request Parameters

Send data through URL for API requests:

// JSON data
{
  "search": "javascript",
  "category": "programming",
  "sort": "date",
  "limit": 10
}

// Query String for GET request
// GET /api/posts?search=javascript&category=programming&sort=date&limit=10

2. Search and Filtering

Create shareable URLs with search parameters:

// Search filters
{
  "query": "laptop",
  "priceMin": 500,
  "priceMax": 1500,
  "brand": "Apple",
  "inStock": true
}

// Shareable URL
// https://store.com/search?query=laptop&priceMin=500&priceMax=1500&brand=Apple&inStock=true

3. Form Submission

Convert form data for URL-based submission:

// Form data
{
  "name": "John Doe",
  "email": "[email protected]",
  "newsletter": true,
  "interests": ["tech", "sports"]
}

// Query String
// name=John%20Doe&email=john%40example.com&newsletter=true&interests=tech&interests=sports

4. State Management

Store application state in URL for bookmarking and sharing:

// Application state
{
  "tab": "profile",
  "userId": 123,
  "page": 2,
  "view": "grid"
}

// URL with state
// https://app.com/dashboard?tab=profile&userId=123&page=2&view=grid

Conversion Rules

1. Basic Data Types

Strings

// JSON
{"name": "John Doe", "city": "New York"}

// Query String
name=John%20Doe&city=New%20York

Numbers

// JSON
{"age": 30, "price": 29.99}

// Query String
age=30&price=29.99

Booleans

// JSON
{"active": true, "verified": false}

// Query String
active=true&verified=false

Null Values

// JSON
{"optional": null}

// Query String (options)
// Option 1: Skip null values
// (empty - no parameter)

// Option 2: Include as empty
optional=

// Option 3: Include as string
optional=null

2. Arrays

Arrays can be handled in several ways:

// JSON
{"colors": ["red", "blue", "green"]}

// Query String
colors=red&colors=blue&colors=green

Comma-Separated Values

// JSON
{"tags": ["javascript", "programming", "web"]}

// Query String
tags=javascript,programming,web

Indexed Parameters

// JSON
{"items": ["apple", "banana", "orange"]}

// Query String
items[0]=apple&items[1]=banana&items[2]=orange

3. Nested Objects

Objects need to be flattened using various strategies:

Dot Notation

// JSON
{
  "user": {
    "name": "John",
    "address": {
      "city": "New York",
      "zip": "10001"
    }
  }
}

// Query String
user.name=John&user.address.city=New%20York&user.address.zip=10001

Bracket Notation

// JSON
{
  "filter": {
    "price": {"min": 100, "max": 500},
    "category": "electronics"
  }
}

// Query String
filter[price][min]=100&filter[price][max]=500&filter[category]=electronics

4. URL Encoding

Special characters must be URL-encoded:

// JSON
{
  "email": "[email protected]",
  "message": "Hello & welcome!",
  "url": "https://example.com/path?param=value"
}

// Query String (URL-encoded)
email=user%40example.com&message=Hello%20%26%20welcome%21&url=https%3A//example.com/path%3Fparam%3Dvalue

Conversion Examples

Example 1: Simple API Query

JSON Input:

{
  "search": "web development",
  "category": "tutorials",
  "language": "javascript",
  "level": "beginner",
  "free": true,
  "page": 1,
  "limit": 20
}

Query String Output:

search=web%20development&category=tutorials&language=javascript&level=beginner&free=true&page=1&limit=20

Full URL:

https://api.courses.com/search?search=web%20development&category=tutorials&language=javascript&level=beginner&free=true&page=1&limit=20

Example 2: E-commerce Product Filter

JSON Input:

{
  "query": "laptop",
  "filters": {
    "price": {
      "min": 500,
      "max": 2000
    },
    "brand": ["Apple", "Dell", "HP"],
    "features": {
      "ssd": true,
      "touchscreen": false,
      "weight": {"max": 2.5}
    },
    "rating": 4
  },
  "sort": "price_asc",
  "page": 2
}

Query String Output (Dot Notation):

query=laptop&filters.price.min=500&filters.price.max=2000&filters.brand=Apple&filters.brand=Dell&filters.brand=HP&filters.features.ssd=true&filters.features.touchscreen=false&filters.features.weight.max=2.5&filters.rating=4&sort=price_asc&page=2

Query String Output (Bracket Notation):

query=laptop&filters[price][min]=500&filters[price][max]=2000&filters[brand]=Apple&filters[brand]=Dell&filters[brand]=HP&filters[features][ssd]=true&filters[features][touchscreen]=false&filters[features][weight][max]=2.5&filters[rating]=4&sort=price_asc&page=2

Example 3: User Registration Form

JSON Input:

{
  "personalInfo": {
    "firstName": "John",
    "lastName": "Doe",
    "email": "[email protected]",
    "phone": "+1-555-123-4567"
  },
  "preferences": {
    "newsletter": true,
    "notifications": {
      "email": true,
      "sms": false,
      "push": true
    },
    "interests": ["technology", "sports", "travel"]
  },
  "terms": true,
  "referralCode": null
}

Query String Output:

personalInfo.firstName=John&personalInfo.lastName=Doe&personalInfo.email=john.doe%40email.com&personalInfo.phone=%2B1-555-123-4567&preferences.newsletter=true&preferences.notifications.email=true&preferences.notifications.sms=false&preferences.notifications.push=true&preferences.interests=technology&preferences.interests=sports&preferences.interests=travel&terms=true

Example 4: Analytics Tracking Parameters

JSON Input:

{
  "event": "page_view",
  "properties": {
    "page": "/products/laptop-123",
    "referrer": "https://google.com/search?q=best+laptop",
    "user": {
      "id": "user_456",
      "segment": "premium"
    },
    "device": {
      "type": "desktop",
      "os": "Windows 10",
      "browser": "Chrome"
    }
  },
  "timestamp": "2024-01-15T10:30:00Z",
  "sessionId": "session_789"
}

Query String Output:

event=page_view&properties.page=%2Fproducts%2Flaptop-123&properties.referrer=https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Dbest%2Blaptop&properties.user.id=user_456&properties.user.segment=premium&properties.device.type=desktop&properties.device.os=Windows%2010&properties.device.browser=Chrome&timestamp=2024-01-15T10%3A30%3A00Z&sessionId=session_789

Conversion Strategies

1. Flat Conversion (Simple)

Only handle primitive values, skip nested objects:

// JSON
{
  "name": "John",
  "age": 30,
  "address": {"city": "NYC"}, // Skipped
  "tags": ["a", "b"]          // Skipped
}

// Query String
name=John&age=30

2. Shallow Flatten

Convert first-level objects only:

// JSON
{
  "user": {"name": "John", "age": 30},
  "settings": {"theme": "dark"}
}

// Query String
user.name=John&user.age=30&settings.theme=dark

3. Deep Flatten

Convert all nested levels:

// JSON
{
  "a": {
    "b": {
      "c": {
        "d": "value"
      }
    }
  }
}

// Query String
a.b.c.d=value

Handling Special Cases

1. Empty Values

// JSON
{
  "emptyString": "",
  "emptyArray": [],
  "emptyObject": {},
  "nullValue": null
}

// Query String Options:
// Include empty values
emptyString=&emptyArray=&emptyObject=

// Skip empty values
// (no parameters)

// Convert to special markers
emptyArray=__EMPTY_ARRAY__&emptyObject=__EMPTY_OBJECT__

2. Duplicate Keys

// JSON with array
{"color": ["red", "blue"]}

// Query String (duplicate keys)
color=red&color=blue

// Alternative (comma-separated)
color=red,blue

3. Reserved Characters

// JSON
{
  "query": "search term with spaces",
  "url": "https://example.com?param=value",
  "special": "chars: !@#$%^&*()"
}

// Query String (properly encoded)
query=search%20term%20with%20spaces&url=https%3A%2F%2Fexample.com%3Fparam%3Dvalue&special=chars%3A%20%21%40%23%24%25%5E%26%2A%28%29

Implementation Examples

JavaScript

// Simple flat conversion
function jsonToQueryString(obj) {
  const params = new URLSearchParams();
  
  for (const [key, value] of Object.entries(obj)) {
    if (value !== null && value !== undefined) {
      if (Array.isArray(value)) {
        value.forEach(item => params.append(key, item));
      } else {
        params.append(key, value);
      }
    }
  }
  
  return params.toString();
}

// Usage
const data = {
  name: "John Doe",
  age: 30,
  colors: ["red", "blue"]
};

console.log(jsonToQueryString(data));
// Output: name=John+Doe&age=30&colors=red&colors=blue

JavaScript with Nested Objects

function flattenObject(obj, prefix = '') {
  const flattened = {};
  
  for (const [key, value] of Object.entries(obj)) {
    const newKey = prefix ? `${prefix}.${key}` : key;
    
    if (value === null || value === undefined) {
      continue; // Skip null/undefined values
    } else if (Array.isArray(value)) {
      value.forEach((item, index) => {
        if (typeof item === 'object') {
          Object.assign(flattened, flattenObject(item, `${newKey}[${index}]`));
        } else {
          flattened[newKey] = flattened[newKey] || [];
          if (!Array.isArray(flattened[newKey])) {
            flattened[newKey] = [flattened[newKey]];
          }
          flattened[newKey].push(item);
        }
      });
    } else if (typeof value === 'object') {
      Object.assign(flattened, flattenObject(value, newKey));
    } else {
      flattened[newKey] = value;
    }
  }
  
  return flattened;
}

function jsonToQueryString(obj) {
  const flattened = flattenObject(obj);
  const params = new URLSearchParams();
  
  for (const [key, value] of Object.entries(flattened)) {
    if (Array.isArray(value)) {
      value.forEach(item => params.append(key, item));
    } else {
      params.append(key, value);
    }
  }
  
  return params.toString();
}

Python

import urllib.parse

def json_to_query_string(data, prefix=''):
    """Convert JSON/dict to query string"""
    params = []
    
    for key, value in data.items():
        param_key = f"{prefix}.{key}" if prefix else key
        
        if value is None:
            continue
        elif isinstance(value, list):
            for item in value:
                params.append(f"{param_key}={urllib.parse.quote(str(item))}")
        elif isinstance(value, dict):
            params.extend(json_to_query_string(value, param_key))
        else:
            params.append(f"{param_key}={urllib.parse.quote(str(value))}")
    
    return params

# Usage
data = {
    "name": "John Doe",
    "filters": {
        "price": {"min": 100, "max": 500}
    },
    "tags": ["tech", "programming"]
}

query_parts = json_to_query_string(data)
query_string = "&".join(query_parts)
print(query_string)

Best Practices

1. Choose Consistent Array Format

// Stick to one format throughout your application

// Option A: Repeated parameters (recommended for most cases)
tags=javascript&tags=python&tags=web

// Option B: Comma-separated (for simple arrays)
tags=javascript,python,web

// Option C: Indexed (for ordered arrays)
tags[0]=javascript&tags[1]=python&tags[2]=web

2. Handle URL Length Limits

// Check query string length (URLs have limits ~2048 chars)
function createQueryString(data) {
  const queryString = jsonToQueryString(data);
  
  if (queryString.length > 2000) {
    console.warn('Query string may be too long for some browsers');
    // Consider using POST request instead
  }
  
  return queryString;
}

3. Sanitize Input Data

function sanitizeValue(value) {
  if (typeof value === 'string') {
    // Remove potentially harmful characters
    return value.replace(/[<>'"]/g, '');
  }
  return value;
}

function safeJsonToQueryString(obj) {
  const sanitized = {};
  for (const [key, value] of Object.entries(obj)) {
    sanitized[key] = sanitizeValue(value);
  }
  return jsonToQueryString(sanitized);
}

4. Consider Server Expectations

// Different servers expect different formats
const configs = {
  php: {
    arrayFormat: 'brackets',    // tags[]=a&tags[]=b
    objectFormat: 'brackets'    // user[name]=John
  },
  rails: {
    arrayFormat: 'repeat',      // tags=a&tags=b
    objectFormat: 'brackets'    // user[name]=John
  },
  express: {
    arrayFormat: 'repeat',      // tags=a&tags=b
    objectFormat: 'dot'         // user.name=John
  }
};

Common Use Cases

1. API Requests

// Building API request URLs
const apiParams = {
  endpoint: 'users',
  filters: {
    active: true,
    role: 'admin'
  },
  pagination: {
    page: 1,
    limit: 20
  }
};

const queryString = jsonToQueryString(apiParams);
const apiUrl = `https://api.example.com/users?${queryString}`;

2. Search Forms

// Converting search form to URL
const searchForm = {
  q: 'javascript tutorial',
  category: 'programming',
  level: 'beginner',
  free: true
};

const searchUrl = `https://courses.com/search?${jsonToQueryString(searchForm)}`;

3. State Persistence

// Saving application state in URL
const appState = {
  currentTab: 'dashboard',
  selectedItems: [1, 2, 3],
  filters: {
    dateRange: '30days',
    status: 'active'
  }
};

window.history.pushState({}, '', `?${jsonToQueryString(appState)}`);

4. Analytics Tracking

// Building tracking URLs
const trackingData = {
  event: 'purchase',
  value: 99.99,
  currency: 'USD',
  userId: 'user123'
};

const trackingUrl = `https://analytics.com/track?${jsonToQueryString(trackingData)}`;

Limitations and Considerations

1. Data Type Loss

  • All values become strings in query strings
  • Need to parse back to original types when receiving

2. URL Length Limits

  • Browsers limit URL length (~2048 characters)
  • Consider POST requests for large data

3. Encoding Issues

  • Special characters need proper URL encoding
  • Unicode characters may cause issues

4. Security Concerns

  • Sensitive data visible in URLs
  • URLs are logged in server logs and browser history

Conclusion

Converting JSON to Query String is essential for:

  • GET request parameters in web APIs
  • Shareable URLs with embedded state
  • Form submissions via URL encoding
  • Search and filtering interfaces

Key considerations:

  • Choose appropriate nesting strategy (dot notation vs brackets)
  • Handle arrays consistently throughout your application
  • Properly encode special characters to avoid URL issues
  • Consider URL length limits for large datasets
  • Be mindful of security when exposing data in URLs

The conversion process transforms structured JSON data into flat key-value pairs suitable for URL transmission while maintaining data integrity and ensuring compatibility with web standards.