Adicionar busca de tickets a um Worker

CloudflareBeginner
Pratique Agora

Introdução

Uma API de suporte precisa localizar tickets abertos e criar, atualizar e remover registros individuais com segurança. Você conectará um Worker ao D1, implementará acesso SQL parametrizado e testará como a API trata registros ausentes e entradas inválidas.

O roteador HTTP já foi fornecido, portanto a tarefa principal é integrar o banco de dados. Este laboratório independente usa um Worker descartável e um banco de dados D1, além de dados locais separados.

Use sua própria conta de aprendizagem e uma VM nova. A configuração prepara o Node.js 22.22.0 e executa npm install para instalar o Wrangler 4.131.1 localmente no projeto e quaisquer dependências da avaliação em /home/labex/project/ticket-database. As versões das dependências diretas estão fixadas; a instalação cria seu próprio lockfile. A configuração não faz login na nuvem nem executa operações avaliadas no banco de dados. Em uma máquina pessoal, instale a mesma versão do Wrangler com npm install --save-dev wrangler@4.131.1 no seu projeto.

Este exercício usa pequenos registros sintéticos dentro dos limites gratuitos do D1. O uso existente da conta também conta para esses limites. Você não precisa de um domínio comprado. Mantenha esta VM até verificar a exclusão dos recursos e o logout.

Autorizar esta VM e selecionar a conta

Nesta etapa, você conectará este terminal novo à sua própria conta de aprendizagem. Fazer login no Dashboard, por si só, não autoriza a VM. A permissão do D1 permite criar bancos de dados, alterar SQL e excluir bancos; a permissão de Workers permite fazer implantações, e a permissão de KV dá suporte ao inventário de limpeza do Wrangler. Revise a página de consentimento exibida, incluindo o acesso em segundo plano (Background Access), antes de autorizar.

Abra o projeto preparado e verifique a versão fixada da CLI:

cd /home/labex/project/ticket-database
npx wrangler --version

O resultado esperado é 4.131.1. Inicie a autorização por dispositivo; --device exibe um código para o navegador, e --browser=false deixa a escolha do navegador para você:

npx wrangler login --device --browser=false --scopes account:read user:read d1:write workers_scripts:write workers_kv:write

Abra a URL exibida no navegador, informe o código atual, confirme sua conta de aprendizagem e as permissões e autorize o acesso. Aguarde o terminal confirmar o sucesso. Nunca cole senhas ou tokens nos arquivos do projeto.

npx wrangler whoami --json

Verifique loggedIn: true e leia o name e o id da conta, mesmo quando apenas uma conta for listada. Copie o ID pretendido para a configuração abaixo. A variável de shell a seguir usa 6 bytes aleatórios (12 caracteres hexadecimais) para evitar conflitos com outros participantes. Um here-document grava o JSON entre as linhas JSON; $RUN é expandida dentro dele.

A barra invertida antes de $schema mantém essa chave JSON literal; $RUN continua sendo expandido para o nome único desta execução.

RUN=labex-c04-d02-$(openssl rand -hex 6)
cat > wrangler.jsonc <<JSON
{
  "\$schema": "./node_modules/wrangler/config-schema.json",
  "name": "$RUN",
  "account_id": "YOUR_ACCOUNT_ID",
  "main": "src/index.js",
  "compatibility_date": "2026-09-15",
  "workers_dev": true,
  "preview_urls": false
}
JSON

Substitua YOUR_ACCOUNT_ID antes de executar o bloco. Mantenha este terminal aberto para que RUN continue disponível. name identifica esta execução; account_id seleciona a conta para as operações na nuvem. O arquivo é um JSON comum, que também é um JSONC válido. Gravá-lo não implanta nenhum Worker.

Preparar dados locais e remotos independentes

Nesta etapa, você criará a conexão com o D1 e preencherá a tabela de tickets conhecida. A configuração fornece o roteamento HTTP e a validação das entradas em src/index.js; as funções de armazenamento ausentes estão em src/store.js. Assim, seu trabalho fica concentrado no acesso SQL.

Crie um banco de dados descartável na nuvem. --binding DB fornece ao código da aplicação um nome curto, --update-config registra o nome real e o UUID em wrangler.jsonc, e --use-remote=false mantém o desenvolvimento local:

npx wrangler d1 create "$RUN-db" --binding DB --update-config --use-remote=false

Leia o nome e o ID criados e depois verifique o binding salvo:

cat wrangler.jsonc

A entrada DB deve indicar o banco de dados desta execução. Um binding é uma conexão configurada entre o código e um recurso. O UUID identifica o banco de dados na nuvem, enquanto --local usa um banco de dados SQLite separado nesta VM. Sempre inclua --local ou --remote nos comandos SQL.

cat schema.sql
npx wrangler d1 execute DB --local --file schema.sql
npx wrangler d1 execute DB --remote --file schema.sql

Agora, cada destino contém os mesmos dois tickets iniciais. DB é o nome que o handler fornecido recebe como env.DB; ele deve corresponder ao binding na configuração.

Implementar CRUD parametrizado

Nesta etapa, você implementará CRUD: criar, ler, atualizar e excluir. Uma instrução preparada mantém a estrutura SQL separada da entrada. Cada ? é um marcador de parâmetro; .bind(...) fornece os valores na ordem. Nunca concatene a entrada do usuário no SQL, mesmo quando ela parecer inofensiva.

WHERE restringe os registros afetados. .all() retorna um objeto de resultado cujo campo results contém o array de linhas. .first() retorna uma linha ou null. A cláusula RETURNING do SQLite devolve a linha alterada sem uma consulta separada. Na exclusão, .run() expõe meta.changes, que informa ao roteador se o registro realmente existia.

Grave o módulo de armazenamento:

cat > src/store.js <<'JS'
export async function list(db, status) {
  const query = status === null
    ? db.prepare('SELECT id, subject, status, source FROM tickets ORDER BY id')
    : db.prepare('SELECT id, subject, status, source FROM tickets WHERE status = ? ORDER BY id').bind(status);
  const { results } = await query.all();
  return results;
}
export async function get(db, id) {
  return db.prepare('SELECT id, subject, status, source FROM tickets WHERE id = ?').bind(id).first();
}
export async function create(db, subject) {
  return db.prepare("INSERT INTO tickets (subject, source) VALUES (?, 'api') RETURNING id, subject, status, source").bind(subject).first();
}
export async function update(db, id, status) {
  return db.prepare('UPDATE tickets SET status = ? WHERE id = ? RETURNING id, subject, status, source').bind(status, id).first();
}
export async function remove(db, id) {
  const result = await db.prepare('DELETE FROM tickets WHERE id = ?').bind(id).run();
  return result.meta.changes === 1;
}
JS

Leia src/index.js para ver como o roteamento fornecido usa essas funções. Registros ausentes se tornam um erro 404 controlado; entradas malformadas se tornam 400; uma falha de banco de dados capturada se torna 503, sem expor detalhes internos do SQL.

Inicie o servidor local como um processo em segundo plano para manter o terminal disponível:

npx wrangler dev --ip 0.0.0.0 > dev.log 2>&1 &

Leia o log de inicialização e aguarde a mensagem indicando que o servidor está escutando:

cat dev.log
curl -i http://localhost:8787/tickets?status=open

O resultado esperado é HTTP 200 e somente o ticket 1. O servidor usa o banco de dados local. Anote o número do job exibido no terminal para fazer a limpeza depois.

Testar gravações e entradas rejeitadas localmente

Nesta etapa, você testará mais do que leituras bem-sucedidas. curl -i mostra o status HTTP e os cabeçalhos; -H fornece o tipo de conteúdo JSON, e -d envia um corpo usando POST por padrão.

Crie um assunto que contenha pontuação semelhante a SQL:

curl -i http://localhost:8787/tickets -H 'Content-Type: application/json' -d "{\"subject\":\"Printer ' OR 1=1 --\"}"

O resultado esperado é 201, com o assunto preservado como dado. Copie o id numérico retornado para TICKET_ID abaixo; não presuma que os IDs continuarão iguais após testes repetidos:

TICKET_ID=YOUR_RETURNED_ID
curl -i http://localhost:8787/tickets/$TICKET_ID
curl -i -X PATCH http://localhost:8787/tickets/$TICKET_ID -H 'Content-Type: application/json' -d '{"status":"closed"}'
curl -i -X DELETE http://localhost:8787/tickets/$TICKET_ID
curl -i http://localhost:8787/tickets/$TICKET_ID

O esperado é uma leitura 200, uma atualização 200 com closed, uma exclusão 204 sem corpo e, em seguida, 404 com {"error":"not_found"}. Os dois tickets originais devem continuar intactos.

Envie um JSON malformado e um status inválido:

curl -i http://localhost:8787/tickets -H 'Content-Type: application/json' -d '{'
curl -i -X PATCH http://localhost:8787/tickets/1 -H 'Content-Type: application/json' -d '{"status":"lost"}'

O resultado esperado é HTTP 400 com invalid_json e invalid_status, respectivamente. A parametrização SQL impede que a entrada se torne SQL, enquanto a validação da aplicação rejeita valores fora das regras de negócio. São problemas diferentes, resolvidos de maneiras diferentes.

Implantar e testar o banco de dados vinculado

Nesta etapa, você publicará o handler e o binding do D1. O banco de dados remoto já foi preenchido; a implantação não copia as linhas locais.

npx wrangler deploy

Copie a URL real https://...workers.dev exibida pela implantação para uma variável de shell. Esta é uma API sintética descartável, portanto remova-a depois dos testes:

URL='YOUR_DEPLOYED_HTTPS_URL'
curl -i "$URL/tickets?status=open"

O resultado esperado é 200 e o ticket 1. Se uma implantação nova retornar temporariamente um erro da plataforma, aguarde alguns segundos e repita esta leitura por até um minuto. Continue somente quando o status e o JSON corresponderem ao esperado; falhas persistentes precisam ser investigadas.

Repita o CRUD na API remota, copiando o ID retornado por ela:

curl -i "$URL/tickets" -H 'Content-Type: application/json' -d '{"subject":"Remote test"}'
TICKET_ID=YOUR_RETURNED_ID
curl -i -X PATCH "$URL/tickets/$TICKET_ID" -H 'Content-Type: application/json' -d '{"status":"closed"}'
curl -i -X DELETE "$URL/tickets/$TICKET_ID"
curl -i "$URL/tickets/$TICKET_ID"
curl -i "$URL/tickets"

O esperado é 201, 200, 204, 404 e, por fim, os dois tickets iniciais sem alterações. No Dashboard, abra exatamente este Worker e a visualização Bindings. Confirme que DB aponta para o seu banco de dados; acesse o link do banco para fazer uma inspeção somente leitura. Um binding salvo localmente não comprova a conexão usada pela implantação.

O Worker implantado e sua vinculação DB

Este exemplo mostra o Worker implantado conectado pelo DB ao seu banco de dados D1. O sufixo aleatório identifica esta execução de exemplo; seus nomes serão diferentes. O link Value da tabela abre o banco de dados selecionado pela vinculação implantada.

Excluir os recursos descartáveis

Nesta etapa, você removerá somente os recursos deste laboratório enquanto a VM ainda estiver autorizada. Conclua primeiro todas as verificações funcionais. Mantenha a configuração até terminar de verificar a exclusão.

npx wrangler delete

Confirme que aparece somente o nome do Worker desta execução na configuração.

npx wrangler d1 delete DB

Inspecione o prompt e confirme que aparece somente o banco de dados desta execução. Em seguida, liste os bancos de dados:

npx wrangler d1 list --json

O nome e o UUID do banco de dados que você registrou devem estar ausentes em uma resposta bem-sucedida. Outros recursos podem permanecer. Um erro de autenticação ou de rede não é conclusivo: resolva o problema de acesso e repita a leitura antes de continuar. Faça a verificação desta etapa enquanto ainda estiver conectado.

Pare também o job de desenvolvimento local. Liste os jobs e encerre somente o job wrangler dev que você iniciou (substitua %1 se o número do job for diferente):

jobs
kill %1

Encerrar a autorização desta VM

Nesta etapa, você encerrará a autorização somente depois que a verificação independente da exclusão for concluída com sucesso. O logout remove a autorização armazenada do Wrangler nesta VM; fechar uma VM, por si só, não faz a limpeza na nuvem.

npx wrangler logout
npx wrangler whoami --json

O resultado esperado é loggedIn: false. Essa consulta sem autenticação pode terminar com um código diferente de zero; isso só é esperado quando a resposta estruturada indicar explicitamente que você está desconectado. Conclua a verificação e depois feche o ambiente do laboratório.

Resumo

Você praticou como adicionar busca de tickets a um Worker. Verificou resultados observáveis do banco de dados, manteve explícitos a conta selecionada e o estado local e removeu os recursos descartáveis antes de fazer logout.