CS Coder
APIs

HTTP e JSON no Delphi: receber uma resposta não é validar um contrato

Implemente uma leitura JSON com validação de tipos e propriedade dos objetos. Depois conecte o parser ao transporte sem confundir status HTTP com dados válidos.

· 4 min de leitura
Objetivo e formato

Distinguir transporte, sintaxe JSON e validade dos campos

Tutorial · prática orientada · Intermediário
Antes de experimentar

Exceções, tipos JSON e noções de HTTP

Unit principal compilada e exercitada com DCC32 37.0, build 37.0.59082.6021. Referência editorial: Delphi 11.3 e 13.2; essas duas versões não foram verificadas individualmente.

Documentação, instalação e limites de Fundamentos em seis units

Experimentar o contrato no navegador

Seu serviço devolveu HTTP 200 e a aplicação tentou ler nome. O campo não existia. O problema ilustra três verificações distintas: a requisição foi atendida, o conteúdo pode ser interpretado e a estrutura corresponde ao contrato que o consumidor espera.

Vamos implementar a terceira parte usando uma resposta fixa. Assim, é possível estudar o parser sem depender de uma rede disponível ou de uma API pública que pode mudar.

Escreva o contrato antes do parser

O contrato deste exercício exige um objeto com nome do tipo string, preenchido após remover espaços. Campos extras serão ignorados. A raiz não pode ser um array, e null não equivale a texto vazio.

json
{"nome":"Ana","ativo":true}

JSON possui tipos próprios, como strings, números, objetos, arrays e null. Para intercâmbio entre sistemas, a especificação exige UTF-8. Isso não define os campos da sua API: esse contrato ainda precisa ser documentado. RFC 8259.

Valide e copie o dado necessário

Crie Api.Nomes.pas:

delphi
unit Api.Nomes;

interface

function LerNomeJSON(const Texto: string): string;

implementation

uses
  System.SysUtils, System.JSON;

function LerNomeJSON(const Texto: string): string;
var
  Raiz: TJSONValue;
  Nome: TJSONValue;
begin
  Raiz := TJSONObject.ParseJSONValue(Texto);
  try
    if not (Raiz is TJSONObject) then
      raise EArgumentException.Create('Objeto JSON esperado');
    Nome := TJSONObject(Raiz).GetValue('nome');
    if not (Nome is TJSONString) then
      raise EArgumentException.Create('nome deve ser uma string');
    Result := Trim(TJSONString(Nome).Value);
    if Result = '' then
      raise EArgumentException.Create('nome não pode ser vazio');
  finally
    Raiz.Free;
  end;
end;

end.

O código libera a raiz criada pelo parser. Nome referencia um valor contido nessa árvore; não é um novo objeto que o consumidor precise liberar separadamente. O retorno é uma string copiada, que pode continuar sendo usada depois da destruição da árvore.

O comportamento de parsing e suas opções devem ser conferidos na referência de ParseJSONValue. A unit foi compilada e os casos da tabela passaram no projeto de verificações, incluindo JSON sintaticamente inválido.

Monte casos antes de integrar a rede

Entrada Expectativa
{"nome":"Ana"} Retorna Ana
{"nome":" Ana "} Retorna Ana
{"nome":42} Rejeita o tipo
{"nome":null} Rejeita o tipo
{} Rejeita campo ausente
[] Rejeita a raiz
Texto inválido Rejeita ou propaga falha de parsing

Teste também campos extras. Se sua API exige rejeitar chaves duplicadas ou limita o tamanho do documento, acrescente uma política explícita; o exemplo acima não implementa essas verificações. Para entrada não confiável, imponha limites antes de carregar uma resposta inteira em memória.

Conecte transporte e contrato em etapas

Quando integrar THTTPClient, defina timeouts e valide o status antes de interpretar um corpo de sucesso. Leia o tipo de conteúdo esperado e trate respostas sem corpo conforme o contrato. Um HTTP 204, por exemplo, não precisa ser um objeto JSON ausente por erro.

Não registre o corpo inteiro para diagnosticar qualquer falha: a resposta pode conter dados pessoais. Prefira contexto da operação, código HTTP e diagnóstico sanitizado.

Timeout não prova que nada aconteceu

Um servidor pode ter aplicado uma gravação antes de a conexão cair. Repetir a requisição pode duplicar a operação. A semântica de idempotência descreve o efeito pretendido de repetir uma mesma requisição; não autoriza repetição indiscriminada de toda operação. RFC 9110, seção 9.2.2.

Para uma escrita, siga o mecanismo previsto pela API, como uma chave de idempotência quando oferecida, e estabeleça como consultar o resultado de uma operação de desfecho incerto.

Experimento e próxima leitura

Crie os casos da tabela em um projeto de console e execute a função sem rede. Só então conecte o transporte. Quando surgir uma falha, você conseguirá dizer em qual etapa ela ocorreu.

Continue em Autenticação e proteção de tokens para analisar a credencial que acompanha a requisição.

Cinco cenários em fronteiras distintas

  1. No laboratório HTTP, compare 200 válido.
  2. 200 com corpo inválido falha na sintaxe.
  3. 204 não tem corpo para interpretar.
  4. 401 indica autenticação recusada.
  5. Timeout deixa desfecho remoto incerto: não repita escrita automaticamente.

Cada fixture explica a fronteira; nenhuma rede é acessada. Campos JSON pertencem à raiz; copie os valores e libere a raiz, não cada campo separadamente.

Agora é com você

Uma resposta HTTP 200 garante que os dados estão corretos?

Compare três respostas: um objeto JSON válido, um JSON sem um campo obrigatório e um texto que não é JSON. Descreva em que etapa cada resposta deve ser rejeitada.

Ver uma pista para começar

O status HTTP descreve a requisição. Depois dele, valide o formato, os campos e os valores do contrato. Um status 200 não garante a validade dos dados.

Não precisa acertar de primeira. Observe o resultado e explique o que mudou.

Leitura relacionada

Outra conexão para investigar

Use uma política de limite de itens para distinguir entrada visual, regra e coordenação, com um exemplo independente de VCL, FMX e UniGUI.

Tela, serviço e domínio: separe decisões sem transformar tudo em camadas ↗

4 min de leitura

Abrir projeto de exemplo ↗