Seu carrinho está vazio no momento!

Introdução
Bem-vindos, futuros arquitetos de sistemas! Sou seu professor PhD e hoje mergulharemos em um dos mecanismos mais vitais para a construção de APIs modernas e flexíveis: as Query Strings. Pense nelas como a chave para desbloquear um mundo de interatividade e controle sobre os dados que sua API expõe.
Analogia do mundo real: O cardápio digital interativo
Imagine que você está em um restaurante sofisticado com um cardápio digital interativo em um tablet. Você não quer ver todos os pratos do restaurante de uma vez. Você deseja ver apenas os “pratos principais”, que sejam “vegetarianos” e que custem “até R$ 50”. O que você faz? Você seleciona filtros e ordenações na interface.
Por trás das cenas, esse aplicativo está enviando solicitações para uma API. Essas seleções (pratos principais, vegetarianos, preço) são traduzidas em Query Strings. Ao invés de uma URL simples como /cardapio, o aplicativo envia algo como /cardapio?tipo=principal&dieta=vegetariana&precoMax=50. É assim que você “pede” informações específicas à API, sem sobrecarregar o sistema com dados irrelevantes.
Por que isso é primordial para APIs modernas
Em um cenário onde a quantidade de dados é gigantesca, e os clientes (front-ends, outros serviços) precisam de informações precisas e customizadas, as Query Strings são fundamentais. Elas permitem que o cliente controle:
- Paginação: “Me dê os itens da página 3, com 10 itens por página.” (
?page=3&limit=10) - Filtros: “Mostre-me apenas produtos da categoria ‘Eletrônicos’.” (
?categoria=eletronicos) - Ordenação: “Ordene os resultados por preço, do menor para o maior.” (
?sort=preco&order=asc) - Busca: “Encontre produtos que contenham ‘smartphone’ no nome.” (
?q=smartphone)
Sem elas, sua API seria rígida e inflexível, forçando os clientes a receberem dados em excesso e a fazerem o processamento do lado do cliente, o que é ineficiente e lento.
O que exatamente você vai praticar nesta aula
Nesta aula, você vai desenvolver uma API Express.js que utiliza Query Strings para filtrar e paginar dados. Aprenderemos a extrair esses parâmetros da URL, validá-los e aplicá-los para refinar a resposta da API. Prepare-se para construir APIs que são verdadeiramente responsivas às necessidades dos seus consumidores!
Contexto no ecossistema Node.js/Express
No universo Node.js com o framework Express.js, a manipulação de Query Strings é incrivelmente simples e poderosa. O Express habilita o acesso a esses parâmetros de forma automática através do objeto req.query, tornando o processo de implementação direto e intuitivo. Essa facilidade é uma das razões pelas quais Express.js é tão popular para construir APIs robustas.
Conceito Fundamental
Vamos aprofundar nossa compreensão das Query Strings. Elas representam uma parte da URL que possibilita o envio de dados adicionais ao servidor em uma solicitação HTTP GET, sem alterar o caminho do recurso em si.
Explicação detalhada do conceito técnico
Uma Query String é um conjunto de pares chave-valor anexados ao final de uma URL. Ela começa com um ponto de interrogação (?), que separa o caminho do recurso dos parâmetros. Cada par chave-valor é separado por um “e comercial” (&).
Exemplo: https://api.meusite.com/produtos?categoria=eletronicos&limite=10&ordenarPor=preco
https://api.meusite.com/produtosé o caminho base (endpoint) do recurso.?marca o início da Query String.categoria=eletronicosé o primeiro par chave-valor.&separa o primeiro par do segundo.limite=10é o segundo par chave-valor.&separa o segundo par do terceiro.ordenarPor=precoé o terceiro par chave-valor.
É relevante notar que os valores dos parâmetros são frequentemente URL-encoded (codificados em URL) para garantir que caracteres especiais (espaços, acentos, etc.) sejam transmitidos corretamente e não quebrem a estrutura da URL. Por exemplo, um espaço se torna %20.
Terminologia correta da indústria
- Parâmetros de Query (Query Parameters): As chaves e seus respectivos valores dentro da Query String (ex:
categoria,eletronicos). - Query String: A parte da URL que contém os parâmetros, começando após o
?. - URL Encoding: O processo de converter caracteres especiais em uma sequência de percent-escapes (
%xx) para que possam ser transmitidos de forma segura em uma URL. - Endpoint: A URL específica onde sua API pode ser acessada (ex:
/produtos).
Casos de uso reais em produção
As Query Strings são onipresentes em APIs de produção de alto calibre:
- E-commerce: Filtragem de produtos (cor, tamanho, marca), busca (nome do produto), paginação de resultados.
- Redes Sociais: Listagem de posts (por usuário, por data), busca de usuários ou hashtags.
- APIs de Clima: Obtenção de dados climáticos para uma cidade específica e período (
/clima?cidade=Londres&data=2023-10-27). - APIs de Mapas: Definição de rotas com parâmetros de origem, destino e tipo de transporte.
Esses exemplos demonstram como as Query Strings viabilizam uma interação dinâmica e precisa entre o cliente e o servidor.
Como isso se integra com outras tecnologias
A integração é bastante fluida:
- Front-end (React, Angular, Vue): Componentes de UI constroem URLs com Query Strings dinamicamente com base nas interações do usuário (filtros, paginação) e usam bibliotecas como
axiosou a APIfetchpara fazer as requisições HTTP. - Bancos de Dados (SQL, NoSQL): Os valores dos parâmetros de Query String são frequentemente usados para construir cláusulas
WHERE,LIMIT,OFFSETou equivalentes em consultas a bancos de dados, filtrando e ordenando os resultados antes de retorná-los. - Outros Microserviços: Serviços internos podem se comunicar entre si, passando critérios de busca e configuração via Query Strings.
Vantagens e desvantagens
Vantagens
- Flexibilidade: Permite que os clientes solicitem exatamente os dados de que precisam, em vez de um conjunto fixo.
- Semântica Clara: A URL pode se tornar mais descritiva sobre o que está sendo solicitado.
- Cacheável: Requisições GET com Query Strings são cacheáveis por proxies e navegadores, otimizando o desempenho.
- Compartilhável: Uma URL com Query Strings pode ser facilmente compartilhada, permitindo que outros vejam os mesmos resultados de pesquisa ou filtro.
Desvantagens
- Segurança Limitada: Dados sensíveis nunca devem ser passados via Query Strings, pois são visíveis no histórico do navegador e nos logs do servidor. Use métodos POST/PUT para isso.
- Tamanho da URL: Existe um limite prático para o comprimento de uma URL. Query Strings muito longas podem causar problemas.
- Complexidade: APIs com muitos parâmetros opcionais podem se tornar complexas para gerenciar e validar.
Implementação Prática
Agora, vamos colocar a mão na massa e construir uma API Express.js que aproveita o poder das Query Strings para filtrar e paginar um conjunto de dados.
Ambiente de Desenvolvimento
Certifique-se de ter o Node.js instalado. Para iniciar um projeto Express.js, crie uma pasta, navegue até ela no terminal e execute:
mkdir minha-api-query
cd minha-api-query
npm init -y
npm install express dotenv winston
O pacote dotenv será usado para gerenciar variáveis de ambiente, e winston para logging profissional (embora usaremos um console.log simples para esta aula, é uma boa prática para produção).
Crie um arquivo .env na raiz do projeto com o seguinte conteúdo:
PORT=3000
Código funcional COMPLETO
Crie um arquivo server.js (ou app.js) com o código abaixo. Este código será totalmente compatível com o HostGator Plano M, pois utiliza padrões de Node.js e Express.js padrão. As “configurações específicas” para HostGator Plano M geralmente se resumem a garantir que o Node.js esteja na versão correta e que o processo seja iniciado corretamente, o que este código faz.
// Carrega as variáveis de ambiente do arquivo .env
require('dotenv').config();
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000; // Define a porta, padrão 3000
// --- Simulação de Banco de Dados (dados em memória) ---
// Em uma aplicação real, você faria consultas a um banco de dados aqui.
const produtos = [
{ id: 1, nome: "Notebook Gamer", categoria: "Eletronicos", preco: 7500, estoque: 15 },
{ id: 2, nome: "Mouse Sem Fio", categoria: "Eletronicos", preco: 150, estoque: 100 },
{ id: 3, nome: "Teclado Mecanico", categoria: "Eletronicos", preco: 400, estoque: 50 },
{ id: 4, nome: "Monitor Ultrawide", categoria: "Eletronicos", preco: 2200, estoque: 20 },
{ id: 5, nome: "Liquidificador", categoria: "Eletrodomesticos", preco: 250, estoque: 80 },
{ id: 6, nome: "Batedeira Planetaria", categoria: "Eletrodomesticos", preco: 600, estoque: 30 },
{ id: 7, nome: "Microondas Inox", categoria: "Eletrodomesticos", preco: 700, estoque: 40 },
{ id: 8, nome: "Camiseta Algodao", categoria: "Vestuario", preco: 80, estoque: 200 },
{ id: 9, nome: "Calca Jeans", categoria: "Vestuario", preco: 180, estoque: 150 },
{ id: 10, nome: "Tenis Esportivo", categoria: "Vestuario", preco: 450, estoque: 70 },
{ id: 11, nome: "Fone de Ouvido Bluetooth", categoria: "Eletronicos", preco: 300, estoque: 90 },
{ id: 12, nome: "Geladeira Duplex", categoria: "Eletrodomesticos", preco: 3500, estoque: 10 },
{ id: 13, nome: "Smart TV 50 polegadas", categoria: "Eletronicos", preco: 2800, estoque: 25 },
{ id: 14, nome: "Jaqueta de Couro", categoria: "Vestuario", preco: 600, estoque: 45 },
{ id: 15, nome: "Forno Eletrico", categoria: "Eletrodomesticos", preco: 900, estoque: 20 }
];
// --- Middleware para logging de requisições ---
// Em produção, usaríamos uma lib como Winston ou Morgan.
app.use((req, res, next) => {
console.log([${new Date().toISOString()}] Requisição recebida: ${req.method} ${req.url});
next(); // Passa a requisição para a próxima middleware ou rota
});
// --- Rota Principal: Listar Produtos com Filtro e Paginação ---
// Exemplo de uso: /produtos?categoria=Eletronicos&page=1&limit=5&minPreco=100&maxPreco=1000
app.get('/api/produtos', (req, res) => {
// Logging da Query String recebida
console.log([LOG] Query String recebida:, req.query);
let resultadosFiltrados = [...produtos]; // Cria uma cópia para não modificar o original
// --- 1. Filtragem por Categoria (opcional) ---
const categoria = req.query.categoria;
if (categoria) {
// Validação básica para garantir que a categoria é uma string
if (typeof categoria !== 'string' || categoria.trim() === '') {
console.error('[ERRO] Categoria inválida:', categoria);
return res.status(400).json({
error: 'Parâmetro de categoria inválido. Deve ser uma string não vazia.'
});
}
// Aplica o filtro de categoria (case-insensitive para melhor usabilidade)
resultadosFiltrados = resultadosFiltrados.filter(
produto => produto.categoria.toLowerCase() === categoria.toLowerCase()
);
console.log([LOG] Produtos filtrados por categoria '${categoria}'. Total: ${resultadosFiltrados.length});
}
// --- 2. Filtragem por Faixa de Preço (opcional) ---
const minPreco = parseFloat(req.query.minPreco);
const maxPreco = parseFloat(req.query.maxPreco);
if (!isNaN(minPreco) && minPreco >= 0) {
if (typeof req.query.minPreco !== 'string' || !/^\d+(\.\d+)?$/.test(req.query.minPreco)) {
console.error('[ERRO] minPreco inválido:', req.query.minPreco);
return res.status(400).json({ error: 'Parâmetro minPreco inválido. Deve ser um número positivo.' });
}
resultadosFiltrados = resultadosFiltrados.filter(produto => produto.preco >= minPreco);
console.log([LOG] Produtos filtrados por preço mínimo ${minPreco}. Total: ${resultadosFiltrados.length});
}
if (!isNaN(maxPreco) && maxPreco >= 0) {
if (typeof req.query.maxPreco !== 'string' || !/^\d+(\.\d+)?$/.test(req.query.maxPreco)) {
console.error('[ERRO] maxPreco inválido:', req.query.maxPreco);
return res.status(400).json({ error: 'Parâmetro maxPreco inválido. Deve ser um número positivo.' });
}
resultadosFiltrados = resultadosFiltrados.filter(produto => produto.preco <= maxPreco);
console.log([LOG] Produtos filtrados por preço máximo ${maxPreco}. Total: ${resultadosFiltrados.length});
}
// Validação de faixa de preço coerente
if (!isNaN(minPreco) && !isNaN(maxPreco) && minPreco > maxPreco) {
console.error('[ERRO] Faixa de preço incoerente: minPreco > maxPreco');
return res.status(400).json({ error: 'minPreco não pode ser maior que maxPreco.' });
}
// --- 3. Paginação ---
// Valores padrão para page e limit para robustez
const page = parseInt(req.query.page) || 1; // Converte para inteiro, padrão é 1
const limit = parseInt(req.query.limit) || 10; // Converte para inteiro, padrão é 10
// Validação robusta dos parâmetros de paginação
if (isNaN(page) || page < 1) {
console.error('[ERRO] Página inválida:', req.query.page);
return res.status(400).json({ error: 'Parâmetro page inválido. Deve ser um número inteiro positivo.' });
}
if (isNaN(limit) || limit < 1 || limit > 100) { // Limita o 'limit' para evitar sobrecarga
console.error('[ERRO] Limite de itens por página inválido:', req.query.limit);
return res.status(400).json({ error: 'Parâmetro limit inválido. Deve ser um número inteiro entre 1 e 100.' });
}
const startIndex = (page - 1) limit; // Calcula o índice inicial para a página
const endIndex = page limit; // Calcula o índice final
const produtosPaginados = resultadosFiltrados.slice(startIndex, endIndex); // Aplica a paginação
// --- 4. Construção da Resposta ---
const totalProdutos = resultadosFiltrados.length;
const totalPages = Math.ceil(totalProdutos / limit);
res.json({
total: totalProdutos,
paginaAtual: page,
limitePorPagina: limit,
totalPaginas: totalPages,
dados: produtosPaginados,
// Links para facilitar a navegação (melhoria enterprise)
links: {
proximaPagina: page < totalPages ? /api/produtos?page=${page + 1}&limit=${limit}&categoria=${categoria || ''}&minPreco=${minPreco || ''}&maxPreco=${maxPreco || ''} : null,
paginaAnterior: page > 1 ? /api/produtos?page=${page - 1}&limit=${limit}&categoria=${categoria || ''}&minPreco=${minPreco || ''}&maxPreco=${maxPreco || ''} : null
}
});
console.log([LOG] Resposta enviada com ${produtosPaginados.length} produtos da página ${page}.);
});
// --- Rota de fallback para 404 ---
app.use((req, res) => {
console.warn([AVISO] Rota não encontrada: ${req.method} ${req.url});
res.status(404).json({ error: 'Recurso não encontrado. Verifique a URL.' });
});
// --- Inicializa o servidor ---
app.listen(PORT, () => {
console.log(Servidor rodando na porta ${PORT});
console.log(Para testar, acesse: http://localhost:${PORT}/api/produtos);
console.log(Exemplos:);
console.log(- http://localhost:${PORT}/api/produtos?categoria=Eletronicos);
console.log(- http://localhost:${PORT}/api/produtos?page=2&limit=3);
console.log(- http://localhost:${PORT}/api/produtos?categoria=Eletrodomesticos&minPreco=300&maxPreco=700);
console.log(- http://localhost:${PORT}/api/produtos?page=1&limit=5&categoria=Vestuario&minPreco=50&maxPreco=500);
});
Comentários detalhados linha por linha
require('dotenv').config();: Carrega variáveis de ambiente do arquivo.env, crucial para configurações sensíveis ou que mudam entre ambientes.const express = require('express');: Importa o módulo Express.app.use((req, res, next) => { ... });: Um middleware simples de logging para registrar cada requisição. Em um ambiente de produção, uma biblioteca como Winston ou Morgan seria preferível para um log mais estruturado e persistente.const produtos = [...]: Simula um conjunto de dados que normalmente viria de um banco de dados. Para esta aula, um array em memória é suficiente para focar na lógica da Query String.app.get('/api/produtos', (req, res) => { ... });: Define nossa rota principal. Esta função será executada para requisições GET ao endpoint/api/produtos.let resultadosFiltrados = [...produtos];: Inicia um array mutável com todos os produtos. Usamos o operador spread...para criar uma cópia e não modificar o original.const categoria = req.query.categoria;: Esta é a magia! O Express popula o objetoreq.querycom os pares chave-valor da Query String. Se a URL for?categoria=Eletronicos,req.query.categoriaserá"Eletronicos".- Validação de Entrada: Blocos
if (typeof categoria !== 'string' || categoria.trim() === '') { ... }eif (isNaN(page) || page < 1) { ... }são essenciais. Nunca confie nos dados que vêm do cliente. Valide tipos, faixas de valores e formatos para prevenir erros e ataques. parseFloat(req.query.minPreco);/parseInt(req.query.page);: Converte os valores da Query String (que são sempre strings) para o tipo numérico adequado.|| 1e|| 10fornecem valores padrão caso os parâmetros estejam ausentes ou inválidos.resultadosFiltrados.filter(...): Aplica a lógica de filtragem com base nos parâmetros.resultadosFiltrados.slice(startIndex, endIndex);: Realiza a paginação, extraindo uma "fatia" do array com base nos índices calculados.res.status(400).json({ error: 'Mensagem' });: Error handling sólido. Em caso de validação falha, retornamos um status HTTP 400 (Bad Request) e uma mensagem clara de erro. Isso é crucial para que os clientes da API possam entender e corrigir suas requisições.res.json({ ... });: Envia a resposta como um objeto JSON, incluindo metadados da paginação e os links para navegação, uma melhor prática enterprise para APIs paginadas.app.use((req, res) => { ... });: Uma rota de fallback para tratar requisições a URLs não mapeadas (404 Not Found).app.listen(PORT, () => { ... });: Inicia o servidor e exibe as instruções de como testar.
Múltiplas variações e alternativas
- Ordenação (Sorting): Poderíamos adicionar um parâmetro
?sort=preco&order=asc. A lógica envolveria usar o método.sort()emresultadosFiltrados. - Busca por Texto (Search): Um parâmetro
?q=textopoderia filtrar produtos cujos nomes ou descrições contêm o texto de busca, usando.includes()ou expressões regulares. - Múltiplos Valores para o Mesmo Parâmetro: Para filtrar por múltiplas categorias (ex:
?categoria=Eletronicos&categoria=Vestuarioou?categorias=Eletronicos,Vestuario), o Express.js pode automaticamente transformar em um array (se a URL for?categoria=Eletronicos&categoria=Vestuario,req.query.categoriaserá['Eletronicos', 'Vestuario']). Se o formato for separado por vírgulas, você precisaria fazer um.split(',').
Melhores práticas enterprise
- Validação e Saneamento: Sempre valide e, se necessário, saneie os inputs do usuário. Bibliotecas como Joi ou Express-validator podem ajudar a gerenciar a complexidade da validação.
- Default Values (Valores Padrão): Ofereça valores padrão sensatos para parâmetros opcionais (como
page=1,limit=10), tornando a API mais robusta e fácil de usar. - Consistência nos Nomes: Use nomes de parâmetros consistentes e claros (camelCase, snake_case) em toda a sua API.
- Limites Razoáveis: Imponha limites para paginação (ex:
limitmáximo de 100), para evitar que clientes solicitem quantidades excessivas de dados, sobrecarregando o servidor e o banco de dados. - Paginção HATEOAS: Inclua links para páginas próximas/anteriores/primeira/última na resposta da API, como feito no exemplo, capacitando os clientes a navegar pelos recursos.
Configurações específicas para HostGator Plano M
Para o HostGator Plano M, a configuração deste código é direta. Você precisaria:
- Fazer Upload: Enviar os arquivos do seu projeto (
server.js,package.json,.env,node_modules) para o seu servidor. - Instalar Dependências: Se os
node_modulesnão forem enviados, executenpm installno servidor. - Configurar o Processo: O HostGator geralmente oferece um painel de controle (cPanel) onde você pode configurar o "Setup Node.js App". Lá, você apontaria para o arquivo
server.jscomo seu arquivo de inicialização e definiria a porta (ou usaria a padrão do ambiente). Oprocess.env.PORTno código irá automaticamente pegar a porta designada pelo ambiente do HostGator. - Versão do Node.js: Certifique-se de que a versão do Node.js configurada no HostGator seja compatível com a que você desenvolveu.
Nenhuma alteração no código acima é necessária para compatibilidade, pois ele segue as práticas padrão do ecossistema Node.js/Express.
Testes básicos incluídos
Para testar a API, salve o código como server.js e execute no terminal:
node server.js
Em seguida, abra seu navegador ou use uma ferramenta como curl para fazer as seguintes requisições:
- Listar todos os produtos: http://localhost:3000/api/produtos
- Filtrar por categoria "Eletronicos": http://localhost:3000/api/produtos?categoria=Eletronicos
- Paginação: página 2, limite de 3 itens: http://localhost:3000/api/produtos?page=2&limit=3
- Combinar filtro e paginação: http://localhost:3000/api/produtos?categoria=Vestuario&page=1&limit=2
- Filtrar por faixa de preço: http://localhost:3000/api/produtos?minPreco=300&maxPreco=700
- Testar erro de validação (página inválida): http://localhost:3000/api/produtos?page=0
- Testar erro de validação (limite inválido): http://localhost:3000/api/produtos?limit=abc
Exercício Hands-On
Chegou a hora de você aplicar o que aprendeu. Um verdadeiro especialista não apenas entende, mas também constrói!
Desafio prático para implementar sozinho
Seu desafio é adicionar uma funcionalidade de ordenação à API de produtos.
Implemente dois novos parâmetros de Query String:
sort=nomeousort=preco: Para indicar por qual campo os resultados devem ser ordenados.order=ascouorder=desc: Para indicar se a ordenação deve ser ascendente (crescente) ou descendente (decrescente).
Requisitos:
- Se nenhum parâmetro
sortfor fornecido, os produtos devem ser retornados na ordem original (ou porid, se preferir). - Se
sortfor fornecido, masordernão, useasccomo padrão. - Inclua validação robusta para os valores de
sort(apenas 'nome' ou 'preco' são permitidos) eorder(apenas 'asc' ou 'desc'). Retorne um erro 400 em caso de valores inválidos. - A ordenação deve ser aplicada antes da paginação e filtragem.
Solução detalhada passo a passo
Vamos adicionar a lógica de ordenação no arquivo server.js, antes da paginação.
- Extrair e Validar Parâmetros de Ordenação:
Adicione estas linhas no início da sua rota
/api/produtos, logo após a inicialização deresultadosFiltrados:// ... dentro de app.get('/api/produtos', (req, res) => { ... let resultadosFiltrados = [...produtos]; // Cria uma cópia para não modificar o original// --- Nova Seção: Ordenação --- const sort = req.query.sort; // Campo para ordenar (ex: 'nome', 'preco') const order = req.query.order ? req.query.order.toLowerCase() : 'asc'; // Ordem (padrão: 'asc')
// Validação dos parâmetros de ordenação const camposPermitidos = ['nome', 'preco', 'id', 'estoque']; // Adicione 'id' e 'estoque' para mais flexibilidade const ordensPermitidas = ['asc', 'desc'];
if (sort && !camposPermitidos.includes(sort)) { console.error('[ERRO] Parâmetro sort inválido:', sort); return res.status(400).json({ error:
Parâmetro sort inválido. Use um dos seguintes: ${camposPermitidos.join(', ')}.}); }if (order && !ordensPermitidas.includes(order)) { console.error('[ERRO] Parâmetro order inválido:', order); return res.status(400).json({ error:
Parâmetro order inválido. Use 'asc' ou 'desc'.}); }// --- Aplicar Ordenação --- if (sort) { resultadosFiltrados.sort((a, b) => { let valA = a[sort]; let valB = b[sort];
// Tratamento específico para strings (case-insensitive) if (typeof valA === 'string' && typeof valB === 'string') { valA = valA.toLowerCase(); valB = valB.toLowerCase(); }
if (valA < valB) { return order === 'asc' ? -1 : 1; } if (valA > valB) { return order === 'asc' ? 1 : -1; } return 0; // Se forem iguais }); console.log(
[LOG] Produtos ordenados por '${sort}' em ordem '${order}'.); } // ... restante da rota (filtragem, paginação) - Testar a Nova Funcionalidade:
Ajuste os exemplos de teste no
app.listenpara incluir as novas opções.
Como testar e validar o resultado
Após salvar as alterações no server.js e reiniciar o servidor (node server.js), teste com as seguintes URLs:
- Ordenar por preço ascendente: http://localhost:3000/api/produtos?sort=preco&order=asc
- Ordenar por nome descendente: http://localhost:3000/api/produtos?sort=nome&order=desc
- Ordenar por estoque (padrão 'asc'): http://localhost:3000/api/produtos?sort=estoque
- Combinar com filtro e paginação: http://localhost:3000/api/produtos?categoria=Eletronicos&sort=preco&order=desc&page=1&limit=2
- Testar erros (parâmetro
sortinválido): http://localhost:3000/api/produtos?sort=cor
Observe a saída no console do servidor para verificar os logs de ordenação e quaisquer mensagens de erro que possam aparecer.
Troubleshooting dos erros mais comuns
- 400 Bad Request: Geralmente indica um erro de validação nos parâmetros. Verifique se os valores para
sorteorderestão entre os permitidos ('nome', 'preco' e 'asc', 'desc' respectivamente). - Ordenação Incorreta: Verifique a lógica de comparação dentro do
.sort(). Certifique-se de que a comparaçãoa[sort] < b[sort]está correta para o tipo de dado do campo. Para strings, converter para minúsculas antes da comparação garante que "Maçã" e "maçã" sejam tratadas de forma consistente. - Parâmetros não Reconhecidos: Se sua API não responder aos parâmetros
sorteorder, verifique se você digitou corretamentereq.query.sortereq.query.order. Lembre-se que as chaves emreq.querysão sensíveis a maiúsculas e minúsculas.
Próximos passos sugeridos
Você agora domina a base das Query Strings. Para ir além:
- Bibliotecas de Validação: Explore bibliotecas como Joi ou Express-validator para gerenciar a validação de forma mais estruturada e escalável.
- Search Completo (Full-Text Search): Integre uma funcionalidade de busca mais avançada usando Query Strings, talvez com uma biblioteca como Lunr.js (para dados em memória) ou a funcionalidade de busca de um banco de dados (Elasticsearch, MongoDB Atlas Search).
- Otimização de Performance: Quando trabalhando com grandes volumes de dados de um banco de dados, aprenda a traduzir eficientemente Query Strings em queries de banco de dados otimizadas (índices, etc.).
- Documentação da API: Use ferramentas como Swagger/OpenAPI para documentar claramente todos os parâmetros de Query String disponíveis em seus endpoints, tornando sua API fácil de consumir.
Parabéns por completar esta aula significativa! Você deu um passo gigantesco na construção de APIs mais dinâmicas e amigáveis. Continue praticando e explorando!
🚀 Pronto para a próxima aula?
Continue sua jornada no desenvolvimento de APIs e domine Node.js & Express!