Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Query String no Node.js: Guia Prático

Atualizado em: 12 de agosto de 2026

Terminal Linux usado em desenvolvimento e administração de aplicações Node.js

Parâmetros de consulta aparecem depois do caractere ? em uma URL e permitem representar filtros, paginação, ordenação, busca e opções de resposta. O módulo Query String no Node.js oferece funções para transformar esse trecho em objetos e converter objetos novamente em texto.

Embora a API moderna URLSearchParams seja recomendada para muitos projetos novos, o módulo node:querystring continua presente em aplicações legadas e integrações que dependem de regras específicas. Compreender as diferenças evita bugs com valores repetidos, espaços, codificação e objetos complexos.

Neste guia, você aprenderá a usar parse(), stringify(), escape() e unescape(), comparar o módulo com URLSearchParams, validar entrada, limitar parâmetros e evitar vulnerabilidades ou ambiguidades em APIs.

O que é uma query string?

Considere a URL:

https://example.com/products?category=books&page=2&sort=price

A query string é:

category=books&page=2&sort=price

A documentação oficial do módulo Query String descreve a API. Para a abordagem moderna, consulte a documentação de URLSearchParams na MDN.

O guia de URL API no Node.js mostra como analisar endereços completos. Para validar os valores resultantes, veja Zod no TypeScript.

Importando o módulo

const querystring = require('node:querystring');

Em ES Modules:

import querystring from 'node:querystring';

Convertendo texto em objeto

const values = querystring.parse(
  'category=books&page=2&sort=price'
);

console.log(values);

O resultado contém propriedades com strings:

{
  category: 'books',
  page: '2',
  sort: 'price'
}

O valor page não se torna número automaticamente. A aplicação precisa converter e validar.

Valores repetidos

const values = querystring.parse(
  'tag=node&tag=javascript&tag=backend'
);

Chaves repetidas podem resultar em array:

{
  tag: ['node', 'javascript', 'backend']
}

Sua API deve decidir se aceita um valor, vários valores ou rejeita repetição. Não use silenciosamente o primeiro ou o último sem documentar.

Parâmetros vazios

querystring.parse('search=&active')

Parâmetros sem valor e valores vazios podem ser representados de forma semelhante. Diferencie ausência, string vazia e valor padrão de acordo com a regra de negócio.

Separadores personalizados

const values = querystring.parse(
  'name:Ana;role:admin',
  ';',
  ':'
);

O segundo argumento define o separador entre pares e o terceiro define o separador entre chave e valor. Esse recurso é útil em formatos legados, mas não deve ser usado para inventar protocolos ambíguos.

Limite de chaves

const values = querystring.parse(
  input,
  '&',
  '=',
  { maxKeys: 100 }
);

Limitar a quantidade de parâmetros reduz consumo de CPU e memória. Um cliente pode enviar milhares de pares para tentar degradar o serviço.

Convertendo objeto em texto

const text = querystring.stringify({
  category: 'books',
  page: 2,
  sort: 'price'
});

O resultado será semelhante a:

category=books&page=2&sort=price

Objetos aninhados não são representados automaticamente como JSON estruturado. Defina uma convenção explícita.

Arrays

const text = querystring.stringify({
  tag: ['node', 'javascript']
});

O módulo costuma gerar a chave repetida. Ao integrar com outro sistema, confirme se ele espera repetição, vírgulas, colchetes ou JSON.

Codificação de caracteres

querystring.stringify({
  search: 'café com leite'
});

Espaços e caracteres Unicode são codificados para transporte em URLs. Nunca concatene diretamente valores externos:

const unsafe = `search=${userInput}`;

Use APIs de codificação para evitar que caracteres como & e = alterem a estrutura.

escape()

const encoded = querystring.escape('café & chá');

escape() codifica um componente. Para código moderno e simples, encodeURIComponent() geralmente é mais familiar e interoperável.

unescape()

const decoded = querystring.unescape('caf%C3%A9');

Decodificação pode falhar ou produzir resultado inesperado com entrada malformada. Trate erros e limite tamanho antes de processar grandes strings.

URLSearchParams

const params = new URLSearchParams({
  category: 'books',
  page: '2'
});

console.log(params.toString());

URLSearchParams integra diretamente com a classe URL e funciona também em navegadores. Para projetos novos, costuma ser a melhor escolha.

Lendo parâmetros com URL

const url = new URL(
  req.url,
  'https://api.example.com'
);

const page = url.searchParams.get('page');
const tags = url.searchParams.getAll('tag');

Essa abordagem evita separar manualmente caminho e query string.

Diferenças importantes

  • Valores repetidos: URLSearchParams usa getAll().
  • Iteração: URLSearchParams oferece iteradores.
  • Integração: URLSearchParams pertence à URL API.
  • Objetos: querystring retorna objeto simples.
  • Compatibilidade: sistemas legados podem depender da codificação do módulo antigo.

Não migre sem testes de caracteres, repetição e espaços.

Convertendo números

function parsePositiveInteger(value, fallback) {
  const number = Number(value);

  if (!Number.isInteger(number) || number < 1) {
    return fallback;
  }

  return number;
}

Nunca confie em coerção automática. Valores como string vazia, notação científica e números enormes podem produzir resultados inesperados.

Booleanos

function parseBoolean(value) {
  if (value === 'true') return true;
  if (value === 'false') return false;
  return undefined;
}

Boolean('false') retorna verdadeiro porque a string não está vazia. Faça uma conversão explícita.

Enumerações

const allowedSort = new Set([
  'price',
  'name',
  'createdAt'
]);

if (!allowedSort.has(sort)) {
  throw new Error('Ordenação inválida');
}

Essa allowlist impede que o cliente escolha qualquer coluna ou expressão.

Paginação segura

const page = Math.min(
  parsePositiveInteger(params.page, 1),
  10000
);

const limit = Math.min(
  parsePositiveInteger(params.limit, 20),
  100
);

Limites evitam respostas gigantes e consultas caras.

Filtros de banco

Parâmetros de consulta nunca devem ser interpolados diretamente em SQL:

const sql = `SELECT * FROM users WHERE name = '${name}'`;

Use consultas parametrizadas e mapeie apenas filtros permitidos. Veja Pool PostgreSQL no Node.js para conexões e transações.

Prototype pollution

Objetos criados por parsers precisam ser tratados como entrada externa. Evite mesclar valores diretamente em objetos de configuração:

Object.assign(config, parsedInput);

Use uma allowlist de chaves e construa um novo objeto. O comportamento de protótipo depende do parser e da versão, portanto defesa explícita é mais segura.

Objetos aninhados

Uma query como:

filter[name]=Ana&filter[role]=admin

não é automaticamente convertida em objeto aninhado pelo módulo nativo. Bibliotecas externas podem suportar essa sintaxe, mas aumentam a superfície de ataque e a complexidade.

Para APIs públicas, prefira parâmetros simples ou um corpo JSON validado.

Tamanho máximo

Servidores e proxies aplicam limites à linha da requisição. Mesmo antes desse limite, sua aplicação deve rejeitar queries enormes. Uma URL muito longa prejudica logs, caches e observabilidade.

Normalização para cache

Estas URLs podem representar a mesma consulta:

?page=2&sort=name
?sort=name&page=2

Se a chave de cache usa a string bruta, elas geram entradas diferentes. Normalize parâmetros aceitos em uma ordem estável:

const normalized = new URLSearchParams();
normalized.set('page', String(page));
normalized.set('sort', sort);

Assinaturas e webhooks

Ao verificar uma assinatura, não reconstrua a query sem confirmar o algoritmo. Mudanças de ordem, espaços e codificação podem alterar o valor assinado. Use os bytes originais quando o protocolo exigir.

O artigo de Webhooks Seguros com Node.js explica HMAC e comparação correta.

Logs

Não registre a URL completa sem sanitização. Queries podem conter tokens, e-mails, termos de busca e dados pessoais.

function sanitizeSearchParams(params) {
  const safe = new URLSearchParams(params);

  for (const key of ['token', 'key', 'email']) {
    if (safe.has(key)) safe.set(key, '[REDACTED]');
  }

  return safe.toString();
}

Testes

Cubra:

  • valor único;
  • valores repetidos;
  • parâmetro vazio;
  • Unicode;
  • caracteres reservados;
  • número inválido;
  • booleano inválido;
  • chave desconhecida;
  • quantidade excessiva;
  • URL muito longa.

Use o Node Test Runner para automatizar casos.

Exemplo de parser de API

function parseProductQuery(searchParams) {
  const allowed = new Set([
    'page',
    'limit',
    'category',
    'sort'
  ]);

  for (const key of searchParams.keys()) {
    if (!allowed.has(key)) {
      throw new Error(`Parâmetro desconhecido: ${key}`);
    }
  }

  return {
    page: parsePositiveInteger(
      searchParams.get('page'),
      1
    ),
    limit: Math.min(
      parsePositiveInteger(
        searchParams.get('limit'),
        20
      ),
      100
    ),
    category: searchParams.get('category') || undefined,
    sort: searchParams.get('sort') || 'name'
  };
}

Erros comuns

  • Confiar em tipos: todos os valores chegam como texto.
  • Ignorar repetição: arrays podem ser tratados incorretamente.
  • Concatenar manualmente: caracteres reservados quebram a URL.
  • Permitir qualquer chave: filtros e ordenações perigosas entram na consulta.
  • Registrar tokens: segredos aparecem nos logs.
  • Migrar sem testes: codificação pode mudar.
  • Aceitar query ilimitada: CPU, memória e logs são afetados.

Boas práticas

  • Prefira URL e URLSearchParams em projetos novos.
  • Valide tipos explicitamente.
  • Use allowlist de chaves.
  • Limite quantidade e tamanho.
  • Controle paginação.
  • Use consultas parametrizadas.
  • Normalize chaves de cache.
  • Sanitize logs.
  • Teste repetição e Unicode.
  • Documente a convenção para arrays.

Conclusão

O módulo Query String no Node.js permite converter parâmetros de consulta entre texto e objetos, sendo especialmente útil em sistemas legados e integrações com convenções específicas.

Em APIs modernas, URLSearchParams costuma oferecer uma interface mais integrada e previsível. Independentemente da ferramenta, parâmetros continuam sendo entrada não confiável: precisam de limites, conversão explícita, allowlists, consultas parametrizadas e logs sanitizados. Essas práticas transformam uma conveniência de URL em uma interface segura e consistente.

Os 10 Melhores Cursos de Programação de 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita