☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

Mostrar mensagens com a etiqueta Postman. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Postman. Mostrar todas as mensagens

quinta-feira, 26 de dezembro de 2024

📮 O CARTEIRO E O POETA — QUANDO UMA POSTMAN COLLECTION APRENDEU A ENTREGAR CARTAS AO MAINFRAME

 

Bellacosa Mainframe apresenta o postman

☕ Um Café no Bellacosa Mainframe

📮 O CARTEIRO E O POETA — QUANDO UMA POSTMAN COLLECTION APRENDEU A ENTREGAR CARTAS AO MAINFRAME

Postman, Collections, HTTP, REST, JSON, variáveis, autenticação, scripts, testes positivos e negativos, contratos, Runner, CI/CD, z/OS Connect, CICS, COBOL, Db2 — e o dia em que um jovem programador descobriu que receber 200 OK não significava que a carta havia chegado à pessoa certa.



Sob a tutela de O Carteiro e o Poeta, porque uma API também vive de mensagens. Algumas precisam chegar rápido. Outras precisam chegar com segurança. Todas precisam chegar ao destinatário correto.



🎬 PRÓLOGO — TODA API TEM UM CARTEIRO

Imagine uma pequena ilha.

Todas as manhãs, o carteiro percorre as mesmas ruas carregando cartas. Ele conhece os caminhos, as casas, os moradores e os horários.

Até que encontra um poeta.

O poeta não quer simplesmente que uma carta seja transportada.

Ele quer que ela seja compreendida.

Essa pequena diferença explica uma parte enorme do que significa testar APIs.

Quando começamos a usar o Postman, normalmente fazemos algo parecido com um carteiro iniciante:

GET /clientes/123

Clicamos em Send.

Recebemos:

200 OK

E comemoramos:

Funcionou!

Calma, jovem padawan do COBOL.

O servidor respondeu. Isso é tudo que sabemos até agora.

Talvez tenhamos pedido o cliente 123 e recebido o cliente 999.

Talvez o JSON esteja incompleto.

Talvez o saldo esteja errado.

Talvez uma pessoa sem autorização tenha conseguido consultar informações que não deveria.

Talvez o backend tenha consultado o Db2 errado.

Talvez o COBOL tenha devolvido um código de negócio indicando falha e alguma camada intermediária tenha convertido tudo em HTTP 200.

O carteiro entregou alguma coisa.

Ainda precisamos descobrir se entregou a carta correta para a pessoa correta.

E é aqui que nossa história realmente começa.



📬 CAPÍTULO 1 — POSTMAN NÃO É APENAS UM BOTÃO SEND

Para quem começa a trabalhar com APIs, Postman parece uma ferramenta para escrever uma URL, selecionar GET ou POST e apertar Send.

Isso seria como dizer que ISPF serve para editar texto.

Tecnicamente não está completamente errado.

Mas estamos ignorando quase todo o universo existente atrás da ferramenta.

Uma requisição HTTP pode possuir:

Método
URL
Headers
Parâmetros
Autenticação
Body
Scripts
Testes
Variáveis

Por exemplo:

POST /orders
Content-Type: application/json
Authorization: Bearer {{token}}

Body:

{
  "customerId": "12345",
  "productId": "A100",
  "quantity": 2
}

O Postman permite construir essa requisição, enviá-la e analisar a resposta.

Mas o salto de maturidade acontece quando paramos de pensar em requests isolados e começamos a pensar em Collections.

Uma Collection não deveria ser apenas uma pasta cheia de requisições.

Ela pode representar um verdadeiro sistema automatizado de testes da API.

E isso muda completamente o jogo.



🗃️ CAPÍTULO 2 — COLLECTION: A BOLSA DO CARTEIRO

Imagine a bolsa do nosso carteiro.

Não faria sentido jogar dentro dela milhares de cartas aleatoriamente.

Ele organiza:

Distrito
 ├── Rua
 │    ├── Número
 │    └── Destinatário

Uma Collection bem construída também precisa possuir estrutura.

Por exemplo:

Orders API
│
├── 01 - Authentication
│
├── 02 - Customers
│   ├── Create Customer
│   ├── Get Customer
│   └── Update Customer
│
├── 03 - Orders
│   ├── Create Order
│   ├── Get Order
│   ├── Update Order
│   └── Cancel Order
│
└── 04 - Negative Tests
    ├── Invalid Token
    ├── Customer Not Found
    ├── Invalid Quantity
    └── Forbidden User

Perceba uma coisa importante.

Estamos começando a transformar a Collection em algo parecido com uma especificação executável.

Ela documenta o sistema.

Ela executa o sistema.

Ela testa o sistema.

Ela pode ser compartilhada.

E posteriormente poderá entrar em um pipeline.

Isso é muito diferente de guardar meia dúzia de URLs.



✉️ CAPÍTULO 3 — PRIMEIRO ENTENDA A CARTA

Antes de criar uma request, precisamos entender o contrato.

Suponha:

POST /orders

Pergunte:

O que devo enviar?

{
  "customerId": "C123",
  "productId": "P987",
  "quantity": 2
}

O que espero receber?

{
  "orderId": "O456",
  "status": "CONFIRMED"
}

Qual status HTTP deveria aparecer?

Talvez:

201 Created

Agora temos uma expectativa.

Entrada:

customerId
productId
quantity

Saída:

orderId
status

Esse conceito deveria soar extremamente familiar para quem programa COBOL.

Pense em:

01 WS-REQUEST.
   05 WS-CUSTOMER-ID PIC X(10).
   05 WS-PRODUCT-ID  PIC X(10).
   05 WS-QUANTITY    PIC 9(03).

01 WS-RESPONSE.
   05 WS-ORDER-ID    PIC X(10).
   05 WS-STATUS      PIC X(10).

Mudou a tecnologia.

O princípio continua parecido:

existe uma estrutura de entrada e existe uma estrutura esperada de saída.

O programador COBOL chama isso de layout.

O desenvolvedor moderno talvez chame de contrato.

O carteiro chama de endereço.

Se qualquer um deles estiver errado, alguém receberá a correspondência errada.



🌐 CAPÍTULO 4 — 200 OK NÃO SIGNIFICA “TUDO CERTO”

Este talvez seja o conceito mais importante de toda a conversa.

Considere:

GET /customers/123

Resposta:

200 OK

Body:

{
  "customerId": "999",
  "name": "Mario"
}

A camada HTTP funcionou perfeitamente.

Mas a aplicação falhou.

Você pediu:

123

e recebeu:

999

Portanto precisamos testar diferentes níveis.

No Postman podemos escrever:

pm.test("HTTP status is 200", function () {
    pm.response.to.have.status(200);
});

Mas podemos continuar:

const customer = pm.response.json();

pm.test("Customer ID is correct", function () {
    pm.expect(customer.customerId).to.eql("123");
});

Agora não estamos apenas perguntando:

O servidor respondeu?

Estamos perguntando:

O servidor respondeu corretamente?

Essa diferença separa um teste superficial de um teste realmente útil.


🧠 CAPÍTULO 5 — O CARTEIRO DESCOBRE AS REGRAS DE NEGÓCIO

Imagine que criamos um pedido.

A resposta é:

{
  "orderId": "4711",
  "status": "REJECTED"
}

E recebemos:

200 OK

O transporte funcionou.

Mas talvez nossa expectativa fosse:

status = CONFIRMED

Portanto:

const order = pm.response.json();

pm.test("Order must be confirmed", function () {
    pm.expect(order.status).to.eql("CONFIRMED");
});

Isso é extremamente importante em sistemas mainframe.

Porque muitas aplicações antigas possuem códigos internos de retorno.

Um programa pode devolver algo conceitualmente semelhante a:

RETURN-CODE = 04
MESSAGE     = CUSTOMER BLOCKED

Enquanto uma camada REST pode responder:

200 OK

Se testarmos somente HTTP, podemos declarar sucesso para uma transação que o negócio considera fracasso.

O teste precisa conhecer o significado da resposta.

O poeta não quer saber apenas se a carta chegou.

Ele quer saber se Beatrice leu o poema certo.


📐 CAPÍTULO 6 — TESTANDO O CONTRATO

Agora podemos subir outro degrau.

Não queremos verificar somente valores.

Também queremos verificar estrutura.

Imagine que nossa API deveria responder:

{
  "orderId": "4711",
  "status": "CONFIRMED",
  "amount": 150.00
}

Mas depois de uma alteração recebemos:

{
  "id": 4711,
  "state": "OK"
}

O serviço respondeu.

Mas o contrato mudou completamente.

Isso pode quebrar consumidores.

Imagine um aplicativo esperando:

response.orderId

e alguém muda para:

response.id

Boom.

Não houve necessariamente ABEND no backend.

Mas houve um ABEND conceitual no consumidor.

Schema validation ajuda a detectar mudanças estruturais desse tipo.

Ela pode verificar coisas como:

campo obrigatório
tipo
formato
estrutura

Mas há uma sutileza.

Schema não prova que o conteúdo está correto.

Isto:

{
  "orderId": "9999",
  "status": "CONFIRMED"
}

pode estar estruturalmente perfeito e ainda pertencer ao cliente errado.

Portanto:

Schema Validation
        +
Business Assertions

são complementares.


🔤 CAPÍTULO 7 — VARIÁVEIS: O WORKING-STORAGE DO POSTMAN

Agora começa uma das partes mais interessantes para quem vem do COBOL.

Em vez de escrever:

https://qa.company.com/api/orders/123

podemos utilizar:

{{baseUrl}}/orders/{{orderId}}

E definir:

baseUrl = https://qa.company.com/api
orderId = 123

Podemos possuir ambientes diferentes:

DEV
QA
STAGING

Mudamos o ambiente.

A Collection continua igual.

Isso é poderosíssimo.

Para um programador COBOL, pense nas variáveis como uma espécie de combinação entre parâmetros, configuração e WORKING-STORAGE.

Mas existe uma armadilha.

Variáveis podem existir em diferentes escopos.

Se houver valores duplicados em locais diferentes, podemos executar um teste utilizando um valor que não imaginávamos.

É o equivalente moderno de perguntar:

Quem alterou essa variável?

E descobrir que existem quatro lugares diferentes onde ela poderia ter sido definida.

Dica de sobrevivência:

sempre investigue o valor resolvido, não apenas o nome escrito na request.


🔐 CAPÍTULO 8 — O CARTEIRO PRECISA MOSTRAR O CRACHÁ

APIs modernas frequentemente utilizam tokens.

Por exemplo:

Authorization: Bearer {{accessToken}}

Em vez de configurar autenticação individualmente em cinquenta requests, podemos defini-la na Collection e permitir herança.

Isso reduz repetição.

Mas surge uma distinção fundamental:

Authentication ≠ Authorization

Authentication pergunta:

Quem é você?

Authorization pergunta:

Você pode fazer isso?

Um usuário pode estar perfeitamente autenticado e ainda não possuir autorização para cancelar um pedido.

Por isso os testes precisam explorar situações como:

token ausente
token inválido
token expirado
usuário autenticado sem permissão

E aqui aparece uma pegadinha maravilhosa.

Você cria um teste chamado:

NO TOKEN

remove o token da request...

...e o teste continua funcionando.

Por quê?

Porque a request herdou a autenticação da Collection.

Seu teste negativo acabou sendo positivo sem você perceber.

É o tipo de bug que faz um QA olhar para a tela durante alguns segundos e começar a reconsiderar suas escolhas profissionais.


⚙️ CAPÍTULO 9 — PRE-REQUEST SCRIPT: PREPARANDO A CARTA

Antes de uma request ser enviada, podemos executar scripts.

Por exemplo, gerar um identificador:

const requestId = pm.variables.replaceIn("{{$guid}}");
pm.collectionVariables.set("requestId", requestId);

Depois enviamos:

X-Request-ID: {{requestId}}

Agora cada transação possui uma identidade.

E aqui nossa história chega ao mainframe.

Imagine:

Postman
   ↓
API Gateway
   ↓
z/OS Connect
   ↓
CICS
   ↓
COBOL
   ↓
Db2

Se o mesmo identificador puder ser correlacionado ao longo desse caminho, investigar um problema se torna muito mais poderoso.

Em vez de procurar:

aquela transação que aconteceu mais ou menos às 14:32...

podemos procurar:

Request-ID = 8f7a...

Isso aproxima teste de observabilidade.

E observabilidade é quando o carteiro não sabe apenas que saiu da agência: ele consegue descobrir por quais ruas a carta passou.


🔗 CAPÍTULO 10 — UMA CARTA LEVA À OUTRA

Agora criamos um pedido:

POST /orders

Resposta:

{
  "orderId": "4711"
}

Podemos capturar esse ID:

const body = pm.response.json();

pm.collectionVariables.set(
    "orderId",
    body.orderId
);

A próxima request utiliza:

GET /orders/{{orderId}}

Depois:

PUT /orders/{{orderId}}

Finalmente:

DELETE /orders/{{orderId}}

Criamos um workflow:

CREATE
   ↓
READ
   ↓
UPDATE
   ↓
DELETE

Isso é muito mais poderoso do que requests isoladas.

Estamos testando uma jornada.


💣 CAPÍTULO 11 — TESTE O QUE DEVERIA DAR ERRADO

Desenvolvedores naturalmente gostam de testar:

entrada correta → resultado correto

Mas sistemas reais vivem no território de:

entrada errada
campo ausente
valor máximo
valor mínimo
token expirado
registro inexistente
duplicidade
timeout
permissão insuficiente

Um excelente princípio é:

altere uma condição de cada vez.

Se você alterar cinco coisas simultaneamente e receber erro, não saberá qual delas provocou o comportamento.

Comece com um baseline válido.

Depois altere somente:

quantity = -1

Depois:

quantity = 0

Depois:

quantity = 1

E chegamos aos testes de fronteira.


📏 CAPÍTULO 12 — COBOL ADORA FRONTEIRAS

Suponha:

05 WS-AGE PIC 9(02).

O campo possui limitações claras.

Em APIs também precisamos pensar em limites.

Se uma regra aceita valores entre 1 e 100:

MIN - 1 = 0
MIN     = 1
MIN + 1 = 2

MAX - 1 = 99
MAX     = 100
MAX + 1 = 101

Não teste apenas:

50

O valor 50 provavelmente funciona.

Os monstros costumam morar nas bordas.

Esse princípio aparece em praticamente todas as gerações de computação.

Cartão perfurado, COBOL, Db2, Java, REST ou JSON: limites continuam sendo lugares maravilhosos para encontrar bugs.


📚 CAPÍTULO 13 — UMA REQUEST, CEM CARTAS

Imagine testar:

quantity

com dezenas de valores.

Não queremos duplicar a mesma request cinquenta vezes.

Podemos usar dados externos.

Por exemplo:

quantity,expectedStatus
1,201
2,201
0,400
-1,400
101,400

No teste:

const expected =
    Number(pm.iterationData.get("expectedStatus"));

pm.test("Expected HTTP status", function () {
    pm.expect(pm.response.code).to.eql(expected);
});

Agora temos data-driven testing.

A lógica do teste permanece.

Os dados mudam.

Programadores COBOL deveriam reconhecer imediatamente a beleza disso.

É quase como um processamento batch:

READ INPUT
PERFORM PROCESS-RECORD
PERFORM VALIDATE
READ NEXT

O Postman Runner passa a executar diferentes iterações sobre a mesma lógica.

O velho batch está sorrindo discretamente no fundo da sala.


🏃 CAPÍTULO 14 — COLLECTION RUNNER: O BATCH DAS APIs

Chega uma hora em que clicar em Send deixa de fazer sentido.

Temos:

20 requests
50 datasets
30 assertions
4 workflows

Queremos executar tudo.

É aí que entra o Runner.

Conceitualmente:

Inicializa
   ↓
Carrega ambiente
   ↓
Executa request
   ↓
Executa testes
   ↓
Armazena variáveis
   ↓
Executa próxima request
   ↓
Gera resultados

Parece familiar?

Claro.

Isso é praticamente a filosofia batch reaparecendo em roupas modernas.

A tecnologia mudou.

A ideia de processamento repetível e automatizado continua conosco.


🧹 CAPÍTULO 15 — O FANTASMA DO ESTADO ANTERIOR

Um dos bugs mais traiçoeiros em testes automatizados é o estado residual.

Imagine que ontem:

orderId = 4711

Hoje o POST falha.

Mas a variável ainda contém:

4711

A próxima request executa:

GET /orders/4711

e funciona.

Resultado?

Parece que o workflow passou.

Mas estamos consultando o pedido de ontem.

Esse é um falso positivo perigosíssimo.

Por isso suítes maduras precisam pensar em:

setup
execução
validação
cleanup

Teste repetível significa:

posso executá-lo novamente sem depender dos fantasmas deixados pela execução anterior.


🔦 CAPÍTULO 16 — DEBUGUE NA ORDEM CERTA

Quando algo falhar, não comece alterando JavaScript aleatoriamente.

Siga uma investigação disciplinada:

Endpoint
   ↓
Environment
   ↓
Variáveis resolvidas
   ↓
Authentication
   ↓
Headers
   ↓
Request body
   ↓
Response
   ↓
Scripts
   ↓
Dados
   ↓
Ordem do workflow

Se funciona individualmente mas falha no Runner, desconfie especialmente de:

ordem
estado
variáveis
dados
dependências

Essa disciplina lembra investigação de incidente no mainframe.

Você não começa culpando o COBOL.

Primeiro reconstrói o caminho.


📖 CAPÍTULO 17 — UMA COLLECTION DEVE SOBREVIVER AO SEU CRIADOR

Chegamos a uma pergunta excelente:

Se eu entregar minha Collection para outro desenvolvedor, ele consegue executá-la?

Se a resposta for:

“Sim, mas primeiro preciso explicar umas quinze coisas...”

a documentação ainda não está boa.

Explique:

objetivo
pré-requisitos
ambiente
autenticação
variáveis
ordem de execução
dados necessários
resultado esperado

Inclua exemplos.

Remova segredos.

Nunca transforme uma Collection compartilhada em cofre de:

password
API key
client secret
token permanente

Uma suíte de testes também é código.

Trate-a como tal.


🚂 CAPÍTULO 18 — A COLLECTION ENTRA NO CI/CD

Aqui acontece a grande transformação.

Antes:

Programador
   ↓
Postman
   ↓
Send

Depois:

Commit
   ↓
Build
   ↓
Deploy QA
   ↓
API Tests
   ↓
Resultado
   ↓
Pipeline continua ou falha

Agora o teste deixa de depender de alguém lembrar de apertar um botão.

Podemos executar smoke tests depois do deploy.

Podemos executar regressão.

Podemos impedir que uma mudança incompatível avance silenciosamente.

Em um ambiente mainframe moderno, podemos imaginar:

Git
 ↓
COBOL + COPYBOOK
 ↓
DBB / Build
 ↓
Deploy
 ↓
z/OS Connect
 ↓
Postman API Tests
 ↓
CICS
 ↓
COBOL
 ↓
Db2

O COBOL não deixou de ser COBOL.

O mainframe não deixou de ser mainframe.

Nós simplesmente construímos uma estrada moderna até ele.


🧬 CAPÍTULO 19 — O MAPA MENTAL DO PROGRAMADOR COBOL

Se você está começando em APIs, guarde esta tradução mental:

POSTMAN                    COBOL / MAINFRAME

Iteration Data       →     Arquivo de entrada
Variables            →     WORKING-STORAGE/configuração
Pre-request Script   →     Inicialização
HTTP Request         →     Chamada/transação
JSON Body            →     Estrutura de dados
Response             →     Estrutura retornada
pm.test              →     Validação
Collection           →     Conjunto organizado de processos
Runner               →     Batch automatizado
Environment          →     DEV / QA / PROD
Workflow             →     Sequência transacional
CI/CD                →     Esteira automatizada
Correlation ID       →     Identidade rastreável da transação

Não são equivalências tecnológicas perfeitas.

São pontes mentais.

E pontes são extremamente úteis quando estamos aprendendo um mundo novo.


🕵️ CAPÍTULO 20 — O NÍVEL QUE QUASE NINGUÉM ENSINA

Existe ainda um passo além.

Imagine que um teste falhou:

POST /payment

Resposta:

500 Internal Server Error

Uma suíte básica informa:

FAILED

Uma engenharia madura pergunta:

Por quê?

Imagine conseguir seguir:

Postman
   │
   │ correlation-id = POETA-0317
   ↓
API Gateway
   ↓
z/OS Connect
   ↓
CICS
   ↓
TRANSACTION ABCD
   ↓
COBOL PAYMENT01
   ↓
Db2
   ↓
SQLCODE -911

Agora não temos apenas automação.

Temos rastreabilidade.

O teste encontrou o sintoma.

A observabilidade mostrou o caminho.

Os logs forneceram evidência.

O mainframe revelou a causa.

🥚 EASTER EGG

Se algum dia encontrar nos exemplos do Bellacosa Mainframe uma transação executada exatamente às:

03:17

não tente corrigir o relógio.

O mainframe sabe perfeitamente que horas são.

Algumas transações simplesmente preferem trabalhar no turno da madrugada.


🎓 EPÍLOGO — O POETA FINALMENTE ENTENDEU O CARTEIRO

No começo de nossa história, tínhamos:

URL
 ↓
Send
 ↓
200 OK

Parecia suficiente.

Depois descobrimos um universo inteiro:

API CONTRACT
      ↓
COLLECTION
      ↓
ENVIRONMENT
      ↓
VARIABLES
      ↓
AUTHENTICATION
      ↓
PRE-REQUEST
      ↓
REQUEST
      ↓
RESPONSE
      ↓
ASSERTIONS
      ↓
SCHEMA
      ↓
BUSINESS RULES
      ↓
NEGATIVE TESTS
      ↓
BOUNDARIES
      ↓
WORKFLOWS
      ↓
DATA-DRIVEN TESTS
      ↓
RUNNER
      ↓
DEBUG
      ↓
DOCUMENTATION
      ↓
CI/CD
      ↓
OBSERVABILITY

Essa é a verdadeira evolução.

Você começa testando uma API.

Depois constrói uma suíte.

Depois transforma essa suíte em regressão.

Depois conecta a regressão ao pipeline.

Finalmente conecta os testes à observabilidade e consegue seguir uma transação desde o mundo distribuído até o programa COBOL que executou a regra de negócio.

E então acontece algo curioso.

A tecnologia mais moderna da arquitetura encontra uma das mais antigas.

JSON encontra COPYBOOK.

REST encontra CICS.

OAuth encontra RACF.

CI/CD encontra COBOL.

Postman encontra z/OS.

E nenhum deles precisa destruir o outro.

Porque modernizar mainframe não significa necessariamente arrancar o coração da aplicação e reescrevê-lo.

Às vezes significa simplesmente construir melhores caminhos para chegar até ele.

É justamente aí que O Carteiro e o Poeta se torna uma metáfora perfeita.

O carteiro domina o transporte.

O poeta domina o significado.

Uma boa API precisa dos dois.

Não basta entregar bytes.

Precisamos entregar os bytes certos, ao serviço certo, com a identidade certa, na sequência certa, respeitando o contrato certo e produzindo o resultado de negócio esperado.

Da próxima vez que o Postman mostrar:

200 OK

não feche o teste.

Olhe para aquele verde bonito e pergunte:

“Muito bem, carteiro. Você entregou a carta. Agora me prove que entregou a carta certa.”

☕ Porque no Bellacosa Mainframe, até uma API precisa apresentar evidências antes de sair da War Room.

quarta-feira, 8 de dezembro de 2021

🤖 NATHAN BATEMAN E A API QUE ACHAVA QUE ERA HUMANA

 

Bellacosa Mainframe e o teste de api

☕ Um Café no Bellacosa Mainframe

🤖 NATHAN BATEMAN E A API QUE ACHAVA QUE ERA HUMANA

HTTP, REST, JSON, Postman, OpenAPI, testes positivos e negativos, OAuth, RACF, Db2, CICS, COBOL, contratos, performance, segurança, CI/CD, observabilidade — e o dia em que um programador COBOL descobriu que receber 200 OK não provava absolutamente nada.

Sob a tutela de Nathan Bateman, de Ex Machina — porque, se existe alguém capaz de olhar para uma interface aparentemente perfeita e perguntar “mas o que realmente está acontecendo atrás dela?”, é Nathan.



🎬 PRÓLOGO — BEM-VINDO À CASA, PROGRAMADOR

A porta se fecha atrás de você.

Não existe maçaneta.

À sua frente há vidro, concreto, câmeras, servidores e uma quantidade desconfortável de tecnologia escondida nas paredes.

Nathan coloca uma cerveja sobre a mesa.

— Você programa COBOL?

— Sim.

— CICS?

— Sim.

— Db2?

— Também.

Ele sorri.

— Excelente. Então hoje você vai testar uma API.

Você olha para ele como se tivesse acabado de pedir para compilar Java usando um IBM 029.

API?

REST?

JSON?

Bearer Token?

OpenAPI?

Postman?

Você passou anos pensando em:

COBOL
JCL
CICS
Db2
VSAM
RACF
MQ

E agora aparece uma tela mostrando:

POST /api/v1/payments

Nathan aponta para o monitor.

{
  "account": "123456",
  "amount": 500.00
}

Depois surge:

HTTP/1.1 200 OK

Nathan pergunta:

— Funcionou?

Você responde imediatamente:

— Sim.

Ele sorri novamente.

Era uma armadilha.

Porque acabamos de cometer um dos erros mais perigosos em testes de APIs:

confundir uma resposta tecnicamente bem-sucedida com uma transação de negócio corretamente executada.

Bem-vindo ao laboratório.

Hoje não vamos apenas aprender API Testing.

Vamos descobrir o que existe atrás do vidro.



🧠 CAPÍTULO 1 — A API É AVA?

Em Ex Machina, Caleb inicialmente vê Ava através de uma interface.

Existe uma parede entre eles.

Ele conversa com ela.

Ela responde.

Pergunta:

Caleb
  ↓
interface
  ↓
Ava

Para Caleb, aquilo parece simples.

Mas por trás da interface existe uma quantidade enorme de tecnologia que ele não vê.

Uma API funciona de maneira parecida.

Imagine um aplicativo bancário.

O usuário toca:

CONSULTAR SALDO

O aplicativo envia:

GET /accounts/12345/balance

Recebe:

{
  "account": "12345",
  "balance": 7342.91
}

Para o celular, acabou.

Mas nós somos profissionais de mainframe.

Queremos abrir a parede.

Talvez exista:

APP MOBILE
    ↓
INTERNET
    ↓
API GATEWAY
    ↓
z/OS CONNECT
    ↓
CICS
    ↓
COBOL
    ↓
DB2

Ou:

API
 ↓
IMS
 ↓
COBOL
 ↓
IMS DB

Ou ainda:

API
 ↓
CICS
 ↓
COBOL
 ↓
MQ
 ↓
OUTRO SISTEMA

Essa é a primeira lição.

API não substitui necessariamente o mainframe. API pode simplesmente fornecer uma nova porta para chegar até ele.



🔌 CAPÍTULO 2 — API NÃO É MÁGICA

API significa Application Programming Interface.

Em termos simples, ela estabelece uma forma definida para dois softwares conversarem.

Temos:

CLIENTE
   |
 REQUEST
   ↓
  API
   |
 PROCESSAMENTO
   ↓
 RESPONSE
   |
   ↓
CLIENTE

Para quem vem do COBOL, isso não deveria parecer tão alienígena.

Pense numa COMMAREA.

Um programa recebe uma estrutura:

01 WS-REQUEST.
   05 WS-CUSTOMER-ID PIC 9(10).
   05 WS-OPERATION   PIC X(01).

Processa e devolve:

01 WS-RESPONSE.
   05 WS-RETURN-CODE PIC 9(04).
   05 WS-NAME        PIC X(40).
   05 WS-BALANCE     PIC S9(9)V99 COMP-3.

Uma API também recebe dados e devolve dados.

A representação mudou.

Podemos receber:

{
  "customerId": 123456
}

e responder:

{
  "name": "BELLACOSA",
  "balance": 317.00
}

O jovem programador olha para JSON e pensa:

— Moderníssimo!

O veterano COBOL olha e pensa:

— É um layout de dados usando chaves, colchetes e bastante marketing.

Nathan provavelmente aprovaria a segunda resposta.



🌐 CAPÍTULO 3 — HTTP: O PROTOCOLO QUE CARREGA A CONVERSA

Muitas APIs REST utilizam HTTP.

Uma requisição pode conter:

URL
METHOD
HEADERS
QUERY PARAMETERS
BODY

Exemplo:

POST /customers HTTP/1.1
Host: api.banco.com
Content-Type: application/json
Authorization: Bearer eyJ...

Body:

{
  "name": "Caleb",
  "age": 26
}

Observe as peças.

Endpoint é o endereço lógico do recurso:

/customers

Headers carregam informações adicionais:

Content-Type
Authorization
Accept
Correlation-ID

Body contém os dados enviados.

Isso nos leva aos verbos HTTP.



🛠️ CAPÍTULO 4 — GET, POST, PUT, PATCH E DELETE

Os cinco verbos mais importantes para nosso iniciante são:

GET     consultar
POST    criar/processar
PUT     substituir
PATCH   alterar parcialmente
DELETE  remover

Podemos construir uma analogia COBOL/Db2 apenas para aprendizado:

GET       ≈ SELECT
POST      ≈ INSERT/operação
PUT       ≈ UPDATE completo
PATCH     ≈ UPDATE parcial
DELETE    ≈ DELETE

Mas escreva em letras enormes no caderno:

ANALOGIA NÃO É EQUIVALÊNCIA.

Considere:

POST /payments

Ele talvez execute:

POST
 ↓
z/OS Connect
 ↓
CICS
 ↓
COBOL
 ├── SELECT DB2
 ├── UPDATE DB2
 ├── INSERT DB2
 ├── MQ PUT
 └── COMMIT

Portanto POST não significa necessariamente INSERT.

Ele significa que estamos solicitando determinada operação segundo o contrato daquela API.


🚦 CAPÍTULO 5 — STATUS CODE É O RETURN CODE DA INTERNET?

Mais uma analogia útil, mas imperfeita.

O mainframer conhece:

RC=0000
RC=0004
RC=0008
RC=0012
S0C7
S0C4

HTTP possui famílias de códigos:

1xx → informação
2xx → sucesso
3xx → redirecionamento
4xx → problema relacionado à requisição
5xx → falha do servidor

Alguns essenciais:

200 OK
201 Created
204 No Content

400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
429 Too Many Requests

500 Internal Server Error
503 Service Unavailable

Mas aqui Nathan interrompe a aula.

— Você recebeu 200. Então funcionou?

Não necessariamente.

Veja:

HTTP/1.1 200 OK
{
  "transaction": "FAILED",
  "reason": "INSUFFICIENT_FUNDS"
}

HTTP funcionou.

A API respondeu.

Mas a operação de negócio falhou.

Temos, portanto, pelo menos três perguntas diferentes:

TRANSPORTE
HTTP funcionou?
       ↓
CONTRATO
Resposta possui a estrutura correta?
       ↓
NEGÓCIO
A operação produziu o resultado correto?

Esse pequeno detalhe separa teste superficial de teste sério.


📜 CAPÍTULO 6 — OPENAPI: O COPYBOOK DO MUNDO REST?

Calma.

Não literalmente.

Mas para ensinar COBOL é uma analogia fantástica.

Um copybook pode definir:

01 CUSTOMER.
   05 CUSTOMER-ID     PIC 9(10).
   05 CUSTOMER-NAME   PIC X(40).
   05 CUSTOMER-STATUS PIC X(01).

Uma especificação OpenAPI pode descrever uma representação semelhante:

Customer:
  type: object
  required:
    - customerId
    - customerName
  properties:
    customerId:
      type: integer
    customerName:
      type: string
    status:
      type: string

Antes de testar uma API, leia sua documentação.

Procure:

endpoints
métodos
parâmetros
headers
schemas
autenticação
exemplos
responses
erros

Não comece clicando freneticamente em Send no Postman.

Primeiro descubra qual deveria ser o comportamento.

Teste sem requisito vira adivinhação automatizada.


🧪 CAPÍTULO 7 — POSTMAN: O TERMINAL 3270 DO EXPLORADOR DE APIs

Imagine esta evolução:

3270
 ↓
CICS
 ↓
COBOL

Agora:

Postman
 ↓
HTTP
 ↓
API
 ↓
z/OS Connect
 ↓
CICS
 ↓
COBOL

O Postman permite montar requisições, headers, parâmetros, autenticação e body, além de examinar respostas e organizar chamadas em collections.

Comece simples.

Faça:

GET /customers/123

Clique em Send.

Não comemore ainda.

Inspecione:

status code
headers
body
schema
response time
business rules

Uma resposta não deve ser considerada correta simplesmente porque apareceu alguma coisa na tela.


😊 CAPÍTULO 8 — HAPPY PATH: PRIMEIRO PROVE QUE AVA CONSEGUE CONVERSAR

O teste positivo verifica comportamento esperado com entradas válidas.

Exemplo:

POST /customers
{
  "name": "Nathan Bateman",
  "type": "PREMIUM"
}

Esperamos talvez:

201 Created

e:

{
  "customerId": 12345,
  "name": "Nathan Bateman",
  "type": "PREMIUM"
}

Validamos:

dados válidos
fluxo correto
permissão adequada
resultado esperado
persistência correta

Ótimo.

Mas isso prova apenas que o sistema funciona quando todos se comportam.

Produção não possui essa delicadeza.


😈 CAPÍTULO 9 — O TESTE COMEÇA QUANDO AS COISAS DÃO ERRADO

Agora Nathan fica interessado.

Envie:

{
  "amount": -500
}

Depois:

{
  "amount": "CINCO REAIS"
}

Depois:

{}

Depois:

{
  "amount": null
}

Teste:

  • campos ausentes;

  • tipos inválidos;

  • limites;

  • JSON malformado;

  • dados duplicados;

  • métodos não suportados;

  • valores negativos;

  • valores enormes;

  • strings vazias;

  • recursos inexistentes;

  • credenciais inválidas.

O sistema bom não é aquele que apenas sabe funcionar.

É aquele que sabe falhar corretamente.


💣 CAPÍTULO 10 — PIC 9(7)V99 ENCONTRA JSON

Aqui aparece um problema particularmente interessante para mainframers.

COBOL:

05 WS-AMOUNT PIC 9(7)V99.

API:

{
  "amount": 999999999999999999.99
}

Quem impede isso?

Gateway?

Schema?

z/OS Connect?

Programa intermediário?

COBOL?

Db2?

E se ninguém impedir?

Esse é um maravilhoso teste de boundary.

Teste:

0
0.01
9999999.99
10000000.00
-0.01
NULL
"ABC"

A fronteira é justamente onde muitos defeitos ficam escondidos.


🔐 CAPÍTULO 11 — "QUEM É VOCÊ?" NÃO É "O QUE VOCÊ PODE FAZER?"

Autenticação:

Quem é você?

Autorização:

O que você pode acessar?

Essa distinção é vital.

No IBM Z podemos encontrar uma cadeia como:

OAuth/OIDC
    ↓
API Gateway
    ↓
token
    ↓
z/OS
    ↓
SAF
    ↓
RACF

Mas autenticar alguém não significa permitir qualquer operação.

Teste:

sem token
token inválido
token expirado
token correto
scope incorreto
usuário sem privilégio
usuário privilegiado
recurso de outro usuário

Um 401 e um 403 não significam exatamente a mesma coisa.

E existe uma pergunta ainda mais interessante:

Um usuário autorizado para consultar seus dados consegue trocar /123 por /124 e consultar dados de outra pessoa?

Isso testa autorização no nível do objeto, não apenas login.


🧬 CAPÍTULO 12 — TEST DATA: NÃO USE PRODUÇÃO COMO PARQUINHO

Dados de teste precisam ser:

controlados
repetíveis
realistas
seguros
isolados
limpáveis

No mainframe isso pode ser particularmente delicado.

Existem ambientes com dados acumulados durante décadas.

Você encontrará:

EBCDIC
COMP
COMP-3
campos redefinidos
datas históricas
códigos descontinuados
valores especiais
copybooks antigos
registros migrados

E existe ainda segurança e privacidade.

Mascarar dados sensíveis é fundamental quando dados semelhantes aos de produção precisam alimentar testes.

E nunca coloque senha, token ou segredo dentro do script:

PASSWORD=SUPERSECRET123

Nathan certamente encontraria.

O auditor também.


🗄️ CAPÍTULO 13 — DATABASE VALIDATION: OLHE ATRÁS DO VIDRO

Agora chegamos ao coração do problema.

Você envia:

POST /transfers
{
  "from": "100001",
  "to": "200002",
  "amount": 500.00
}

Recebe:

200 OK

Fim?

Não.

Precisamos descobrir o efeito.

Antes:

A = 2000
B = 1000

Depois:

A = 1500
B = 1500

Precisamos validar:

débito correto
crédito correto
nenhum registro duplicado
histórico criado
mensagem MQ correta
audit trail
commit

Agora provoque uma falha depois do débito e antes do crédito.

O resultado correto provavelmente deverá envolver:

ROLLBACK

e não:

A = 1500
B = 1000

Essa é a diferença entre testar uma tela JSON e testar uma transação.


🔄 CAPÍTULO 14 — COMMIT, ROLLBACK E A UNIT OF WORK

Mainframe conhece esse problema há décadas.

Uma API pode iniciar uma cadeia:

REQUEST
 ↓
CICS
 ↓
COBOL
 ↓
DB2
 ↓
MQ

Agora surgem perguntas realmente interessantes:

O que pertence à mesma unidade de trabalho?

Quando ocorre COMMIT?

O que acontece se MQ falhar?

E se Db2 estiver indisponível?

E se a API sofrer timeout?

E se o cliente repetir a chamada?

Chegamos à palavra que deveria estar colada no monitor de qualquer desenvolvedor de pagamentos:

IDEMPOTÊNCIA

Imagine:

03:16:55 pagamento enviado

03:17:00 processamento iniciado

03:17:10 timeout

O aplicativo não sabe se funcionou.

Então repete.

Se o backend executar novamente:

R$500
R$500

acabamos de cobrar duas vezes.

Uma estratégia pode envolver uma chave de idempotência:

Idempotency-Key: PAY-ABC-123

O backend reconhece a repetição.

E sim: 03:17 apareceu por acaso.

Quem acompanha o Bellacosa Mainframe sabe que acidentes temporais desse tipo costumam ser cuidadosamente planejados. ☕


📐 CAPÍTULO 15 — CONTRACT TESTING: AVA MUDOU A LINGUAGEM

Hoje:

{
  "customerId": 123,
  "status": "ACTIVE"
}

Amanhã alguém decide "modernizar":

{
  "customerNumber": 123,
  "customerStatus": "ACTIVE"
}

O serviço continua funcionando.

Mas dez consumidores quebram.

É o equivalente moderno do sujeito que altera um copybook compartilhado sem estudar impacto e depois pergunta por que metade da madrugada está em conference call.

Contract testing procura detectar mudanças incompatíveis antes que cheguem aos consumidores.

Aqui o mainframer possui uma vantagem cultural enorme.

Ele já conhece o medo saudável de:

"Quem mais usa isso?"


🏎️ CAPÍTULO 16 — PERFORMANCE: 120 MILISSEGUNDOS NÃO CONTAM TODA A HISTÓRIA

Uma API responde em:

120 ms

Excelente.

Com um usuário.

Agora tente 100.

1.000.

10.000.

50.000.

Precisamos observar:

latency — tempo de resposta;

throughput — quantidade processada;

error rate — percentual de falhas;

concurrency — usuários/operações simultâneos.

Existem ainda quatro cenários clássicos:

LOAD
carga normal esperada

SPIKE
explosão repentina

STRESS
além do limite normal

SOAK
carga sustentada durante longo período

No IBM Z, não pare no tempo HTTP.

Investigue:

API Gateway
     ↓
z/OS Connect
     ↓
CICS
     ↓
COBOL
     ↓
Db2
     ↓
CPU / I/O / LOCKS

Pode ser que HTTP esteja apenas mostrando o sintoma.


🕵️ CAPÍTULO 17 — SEGURANÇA: NATHAN NÃO CONFIA NA INTERFACE

API Security Testing precisa procurar problemas como:

autenticação
autorização
input validation
rate limiting
exposição de dados
configurações inseguras

No mainframe adicionamos outra camada:

SAF
RACF
TLS
AT-TLS
certificados
SMF
proteção CICS
privilégios Db2
permissões USS
segregação de funções
auditoria

Um erro particularmente perigoso é retornar informação demais.

Exemplo:

{
  "name": "USER",
  "balance": 500,
  "internalRacfUser": "ABC123",
  "databaseHost": "PRODDB2",
  "debugMessage": "SQLCODE -..."
}

Talvez três desses campos jamais devessem sair dali.

Erro também é dado.

Log também é dado.

Stack trace também é dado.

Portanto teste o que o sistema revela quando falha.


🤖 CAPÍTULO 18 — AUTOMATIZE, MAS NÃO AUTOMATIZE BURRICE

Depois dos testes manuais estáveis, automatizamos.

Ferramentas possíveis incluem:

Postman/Newman
REST Assured
Playwright API
SuperTest

Um framework saudável separa:

config/
api-clients/
test-data/
tests/
reports/

Isso evita aquele script de 4.000 linhas onde URL, senha, payload, teste, relatório e provavelmente o CPF do desenvolvedor estão todos misturados.

Automação boa precisa ser:

repetível
independente
legível
determinística
diagnosticável
manutenível

Automatizar um teste ruim produz um teste ruim que roda mais rápido.


🏭 CAPÍTULO 19 — CI/CD: O COBOL ENTRA NA ESTEIRA

Agora o teste deixa de depender de alguém clicar em Send.

Podemos ter:

COMMIT
   ↓
BUILD
   ↓
UNIT TEST
   ↓
API TEST
   ↓
CONTRACT TEST
   ↓
SECURITY CHECK
   ↓
DEPLOY DEV
   ↓
INTEGRATION TEST
   ↓
QUALITY GATE
   ↓
PROMOTION

Isso também é DevOps no mainframe.

COBOL não precisa deixar de ser COBOL.

CICS não precisa fingir que é Kubernetes.

Db2 não precisa colocar boné para trás.

O objetivo é introduzir práticas modernas de engenharia em torno das plataformas adequadas.


🔭 CAPÍTULO 20 — OBSERVABILIDADE: AVA RESPONDEU, MAS O QUE ELA ESTAVA FAZENDO?

Chegamos ao estágio mais interessante.

Testes dizem:

"Sob estas condições, obtive este resultado."

Observabilidade pergunta:

"O que o sistema está realmente fazendo?"

Precisamos de evidências.

logs
metrics
traces
request IDs
test reports
artifacts

No IBM Z temos uma riqueza enorme de telemetria:

SMF
RMF
CICS statistics
Db2 accounting
Db2 statistics
MQ statistics
WLM
logs
network telemetry

Imagine colocar:

X-Request-ID: CALEB-0317

e acompanhar:

CALEB-0317
    ↓
API Gateway
    ↓
z/OS Connect
    ↓
CICS
    ↓
COBOL
    ↓
Db2

De repente não temos apenas:

"A API demorou 4 segundos."

Temos:

"A requisição chegou ao z/OS, entrou na transação CICS, esperou determinado recurso e a maior parte do tempo foi consumida naquela etapa."

Isso muda completamente a investigação.


🧪 CAPÍTULO 21 — O LABORATÓRIO FINAL DE NATHAN

Sua missão é testar:

POST /accounts/transfer

Payload:

{
  "from": "100001",
  "to": "200002",
  "amount": 500.00
}

Arquitetura:

CLIENT
  ↓
HTTPS
  ↓
API GATEWAY
  ↓
z/OS CONNECT
  ↓
CICS
  ↓
COBOL
  ↓
DB2
  ↓
MQ

Comece pelo happy path.

Depois execute:

conta origem inexistente
conta destino inexistente
saldo insuficiente
amount = 0
amount negativo
amount máximo
amount acima do máximo
amount como texto
campo ausente
JSON quebrado
token ausente
token expirado
scope incorreto
usuário sem autorização
requisição duplicada
timeout
Db2 indisponível
MQ indisponível
100 requests simultâneos
1.000 requests
spike
soak

Depois de cada cenário, pergunte:

HTTP correto?
JSON correto?
Schema correto?
Regra de negócio correta?
Db2 correto?
MQ correto?
Commit correto?
Rollback correto?
RACF correto?
Logs corretos?
SMF mostra o esperado?
Performance aceitável?
Dados sensíveis protegidos?

Agora você não está mais testando simplesmente uma API.

Está testando um serviço de negócio distribuído de ponta a ponta.


🧠 CAPÍTULO 22 — O TESTE DE TURING DO MAINFRAME

Nathan volta à sala.

Na tela aparecem duas respostas:

{
  "status": "SUCCESS"
}

e:

{
  "status": "SUCCESS"
}

São idênticas.

Nathan pergunta:

— Qual delas está correta?

Você não responde.

Abre o Db2.

Verifica a transação CICS.

Consulta evidências.

Confere MQ.

Verifica autorização.

Procura duplicidades.

Analisa logs.

Correlaciona Request ID.

Observa métricas.

Confere o contrato.

Finalmente responde:

— A primeira.

Nathan pergunta:

— Como sabe?

E aí está toda a diferença:

— Porque eu não confiei na interface. Eu validei o sistema.


☕ EPÍLOGO — A API NÃO PRECISAVA SER HUMANA

Existe uma deliciosa ironia nessa história.

Muitos conceitos vendidos como absolutamente modernos são problemas que o mundo mainframe enfrenta há décadas.

Hoje dizemos:

schema

O mainframer lembra de layouts e copybooks.

Hoje:

transaction consistency

Ele pensa em unit of work, commit e rollback.

Hoje:

authorization

Ele pensa em SAF/RACF e também nas regras de autorização da aplicação.

Hoje:

observability

Ele pergunta:

— Quais registros SMF temos?

Hoje:

high availability

Ele sorri.

Hoje:

backward compatibility

Agora ele começa a rir.

Isso não significa que REST, OpenAPI, OAuth, CI/CD ou observabilidade moderna sejam apenas nomes novos para tecnologias antigas. Não são.

Significa algo mais interessante.

Os problemas fundamentais da computação permanecem surpreendentemente constantes:

Quem pediu?

Pode pedir?

Os dados são válidos?

O processamento aconteceu?

A informação foi persistida?

A transação terminou inteira?

Se falhou, voltou ao estado consistente?

Se repetiu, duplicou?

Quanto demorou?

Quantas conseguimos processar?

Quem consegue observar isso?

Quem consegue alterar isso?

Conseguimos provar depois o que aconteceu?

E aqui está talvez a maior lição para o programador COBOL iniciante.

Não tenha medo quando alguém colocar na sua frente:

REST
JSON
OAuth
OpenAPI
Postman
CI/CD
Observability

Você não está abandonando tudo o que aprendeu.

Está aumentando seu campo de visão.

Ontem você enxergava:

3270
 ↓
CICS
 ↓
COBOL
 ↓
DB2

Hoje precisa enxergar:

                    INTERNET
                       │
                       ▼
                  API GATEWAY
                       │
                       ▼
                 z/OS CONNECT
                       │
              ┌────────┴────────┐
              ▼                 ▼
            CICS               IMS
              │                 │
              └───────┬─────────┘
                      ▼
                    COBOL
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
         DB2         VSAM         MQ
          │           │           │
          └───────────┼───────────┘
                      ▼
                COMMIT/ROLLBACK
                      │
                      ▼
               RESPONSE JSON

E ao redor de tudo isso:

        SECURITY
            │
            ▼
   ┌───────────────────┐
   │                   │
RACF/SAF            OAuth
   │                   │
   └─────────┬─────────┘
             │
             ▼
          AUDIT
             │
             ▼
       OBSERVABILITY
             │
     ┌───────┼────────┐
     ▼       ▼        ▼
    SMF     LOGS    METRICS

Essa é a arquitetura que o teste precisa enxergar.

A API é apenas o vidro.

Atrás dela existe uma máquina inteira.


🥚 EASTER EGG — 03:17

Às 03:17, todas as luzes do laboratório apagam.

O programador COBOL continua sentado.

Nathan pergunta:

— Você não está preocupado?

— Não.

— Por quê?

Ele aponta para o monitor.

HTTP 200

Nathan sorri.

O programador responde:

— Também não confio nisso.

Abre outra janela.

CICS: OK
DB2 : COMMIT
MQ  : MESSAGE PUT
RACF: AUTHORIZED
SMF : RECORDED

Então pega o café.

— Agora sim.

Porque no Bellacosa Mainframe existe uma regra que Nathan Bateman aprenderia rapidamente:

Não importa o quão bonita seja a interface, o quão perfeito seja o JSON ou quantos 200 OK apareçam na tela. Em sistemas de missão crítica, confiança não vem da aparência da resposta. Vem da evidência de que toda a cadeia fez exatamente aquilo que deveria fazer.

E talvez esse seja o verdadeiro Teste de Turing de uma API mainframe:

não descobrir se ela consegue parecer inteligente,

mas provar que, quando ninguém está olhando, ela continua sendo correta, segura, consistente, observável e confiável.

☕ Um Café no Bellacosa Mainframe

Onde até Ava teria que apresentar evidência de COMMIT antes de receber acesso à produção.

terça-feira, 19 de junho de 2018

API Status Codes : Quando um Programador Descobre que o Servidor Já Respondeu à Pergunta… Mas Ele Preferiu Consultar Três Logs, Dois Oráculos e um Monge no Deserto

 

Bellacosa Mainframe e o status codes das api numa visão para pequenos gafanhotos

☕ Um Café no Bellacosa Mainframe

API Status Codes sem Mistérios para Programadores COBOL

Quando um Programador Descobre que o Servidor Já Respondeu à Pergunta… Mas Ele Preferiu Consultar Três Logs, Dois Oráculos e um Monge no Deserto

No início da jornada, o jovem programador acreditava que todo erro de API era uma entidade sobrenatural.

Uma criatura invisível.

Um espírito maligno vivendo entre o frontend, o backend, o banco de dados, o firewall, o proxy reverso, o balanceador de carga e aquele serviço terceirizado que ninguém sabia exatamente quem havia contratado.

Quando a aplicação falhava, ele fazia o ritual tradicional:

  1. Reiniciava o navegador.

  2. Limpava o cache.

  3. Reiniciava a aplicação.

  4. Reiniciava o computador.

  5. Culpava a rede.

  6. Culpava o banco de dados.

  7. Culpava o COBOL.

  8. Perguntava à inteligência artificial.

  9. Mandava uma mensagem no grupo da equipe dizendo:
    “Alguém mexeu em produção?”

Então, numa tarde coberta de névoa, enquanto o vento atravessava os corredores do data center e os discos do mainframe giravam como tambores de um templo tecnológico, apareceu o velho mestre.

Ele vestia um quimono gasto, carregava uma caneca de café e segurava nas mãos uma folha contendo quatro símbolos:

2xx
3xx
4xx
5xx

O jovem programador perguntou:

— Mestre, qual é o significado desses números?

O velho respondeu:

— Pequeno gafanhoto, antes de procurar o erro no universo inteiro, leia aquilo que o servidor já lhe disse.

O programador olhou para a tela.

HTTP/1.1 404 Not Found

— Mestre, devo verificar o banco de dados?

— Não.

— O servidor Java?

— Não.

— A aplicação COBOL?

— Não.

— A temperatura da sala do data center?

— Também não.

— Então o que devo verificar?

O mestre tomou um gole de café.

— A URL.

E assim começou a verdadeira arte marcial do debugging de APIs.


O servidor não fala em enigmas

Quando uma API responde, ela não entrega somente dados.

Ela entrega uma estrutura.

Normalmente, uma resposta HTTP possui pelo menos três elementos importantes:

Status
Headers
Body

Por exemplo:

HTTP/1.1 404 Not Found
Content-Type: application/json
X-Correlation-ID: 9812-A7B3

{
  "error": "Cliente não encontrado"
}

O programador iniciante frequentemente olha apenas para o corpo.

O mais apressado olha apenas para a mensagem.

O mais desesperado ignora tudo e abre os logs.

Mas o verdadeiro praticante da arte do debugging observa o conjunto.

O código 404 indica uma classe de problema.

O corpo informa um detalhe.

O cabeçalho X-Correlation-ID pode permitir encontrar a requisição nos logs.

É semelhante a analisar um ABEND em ambiente mainframe.

Receber apenas:

JOB FAILED

não é suficiente.

Você precisa saber:

Qual step?
Qual programa?
Qual return code?
Qual ABEND?
Qual dataset?
Qual mensagem?
Qual horário?
Qual execução?

Em APIs, o status HTTP é como o primeiro código do incidente.

Ele não resolve tudo, mas mostra em qual porta você deve bater.


O caminho completo de uma chamada de API

Muitos desenvolvedores imaginam uma API desta maneira:

Cliente → Servidor

Parece simples.

Quase poético.

Infelizmente, sistemas corporativos raramente possuem a delicadeza de um poema.

O caminho real pode ser:

Aplicação cliente
        ↓
DNS
        ↓
Proxy corporativo
        ↓
Firewall
        ↓
WAF
        ↓
CDN
        ↓
Load balancer
        ↓
API Gateway
        ↓
Servidor web
        ↓
Aplicação
        ↓
Banco de dados
        ↓
Fila
        ↓
Mainframe
        ↓
Outro serviço externo

Quando você recebe um erro, ele pode ter sido produzido por qualquer ponto dessa longa peregrinação.

Um 502, por exemplo, geralmente indica que algum intermediário tentou conversar com outro servidor e recebeu uma resposta inválida.

Um 504 indica que o intermediário esperou, esperou, acendeu uma vela, terminou um café e desistiu.

Um 401 pode ser produzido por um gateway de autenticação antes mesmo de a requisição chegar à aplicação.

Portanto, aprender os códigos HTTP é aprender a localizar o templo onde o problema provavelmente vive.


A primeira família: 1xx — o mensageiro ainda está falando

Os códigos 1xx são pouco vistos no desenvolvimento cotidiano, mas fazem parte do protocolo.

Eles indicam que alguma informação preliminar foi transmitida e que o processo continua.

100 Continue

Imagine que você pretende enviar um arquivo gigantesco para o servidor.

Antes de enviar tudo, o cliente pode perguntar:

Expect: 100-continue

O servidor responde:

HTTP/1.1 100 Continue

Em outras palavras:

“Pode continuar. Ainda não rejeitei sua requisição.”

Isso evita que o cliente envie centenas de megabytes apenas para descobrir depois que não possui autorização.

É como chegar ao portão do mosteiro com vinte caixas e perguntar:

— Posso entrar?

O porteiro responde:

— Continue.

Melhor isso do que carregar tudo até o pátio e descobrir que o templo estava fechado desde 1978.

101 Switching Protocols

Esse código indica mudança de protocolo.

A conexão começou de uma forma e continuará de outra.

É comum em situações de upgrade de comunicação.

103 Early Hints

Permite que o servidor envie pistas antecipadas para o cliente começar a preparar certos recursos antes da resposta final.

É uma espécie de mensagem do mestre:

“Ainda não terminei a explicação, mas já vá abrindo o manual.”


A segunda família: 2xx — a técnica foi executada com sucesso

Os códigos 2xx indicam sucesso sob a ótica do protocolo HTTP.

Mas existe uma diferença importante:

Sucesso HTTP não significa necessariamente sucesso de negócio.

Uma API pode responder 200 OK e, dentro do corpo, informar que uma operação comercial falhou.

Isso é possível, embora frequentemente represente uma API mal projetada.


200 OK

É o sucesso genérico.

Exemplo:

GET /clientes/123

Resposta:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "nome": "Vagner",
  "status": "ativo"
}

A requisição foi atendida e o recurso foi retornado.

No mundo COBOL, seria algo semelhante a:

Programa executado
Registro encontrado
Dados retornados
RETURN-CODE = 0

Mas tome cuidado com respostas como:

HTTP/1.1 200 OK

{
  "success": false,
  "message": "Cliente não encontrado"
}

O protocolo diz sucesso.

O corpo diz falha.

É como um job terminar com CC 0000 e imprimir no relatório:

NENHUM REGISTRO FOI PROCESSADO PORQUE O ARQUIVO ESTAVA CORROMPIDO

Tecnicamente terminou.

Funcionalmente, o castelo está em chamas.

A primeira lição é:

Sempre valide o conteúdo da resposta, não apenas o código.


201 Created

O código 201 indica que um novo recurso foi criado.

Requisição:

POST /clientes
Content-Type: application/json

{
  "nome": "Maria",
  "email": "maria@example.com"
}

Resposta:

HTTP/1.1 201 Created
Location: /clientes/845

{
  "id": 845,
  "nome": "Maria",
  "email": "maria@example.com"
}

O cabeçalho Location informa onde o novo recurso pode ser encontrado.

Analogia mainframe:

200 = a consulta funcionou
201 = um novo registro foi gravado

É como executar um WRITE com sucesso em um arquivo VSAM e receber a chave do registro recém-criado.


202 Accepted

Este é um dos códigos mais importantes para quem conhece processamento batch.

O 202 significa:

“Recebi sua solicitação, aceitei o trabalho, mas ele ainda não terminou.”

Exemplo:

POST /relatorios/mensais

Resposta:

HTTP/1.1 202 Accepted
Location: /tarefas/98271

{
  "taskId": 98271,
  "status": "PROCESSING"
}

Isto é praticamente o equivalente web de:

JOB SUBMITTED

Submeter o job não significa que ele terminou.

Ele pode estar:

INPUT
EXECUTION
OUTPUT
HELD
ABENDED

O iniciante vê 202 e comemora.

O mestre pergunta:

— Onde você consulta o resultado?

O 202 normalmente deve ser acompanhado por algum mecanismo de acompanhamento:

GET /tarefas/98271

Resposta posterior:

{
  "taskId": 98271,
  "status": "COMPLETED"
}

Ou, em um dia menos agradável:

{
  "taskId": 98271,
  "status": "FAILED",
  "error": "Database unavailable"
}

204 No Content

O 204 significa sucesso sem corpo de resposta.

Exemplo:

DELETE /clientes/845

Resposta:

HTTP/1.1 204 No Content

A operação funcionou.

Não existe JSON.

Não existe XML.

Não existe mensagem de parabéns.

O servidor apenas cruza os braços e diz:

“Feito.”

Isso provoca um erro clássico em JavaScript:

const data = await response.json();

Se a resposta é 204, não existe JSON.

Então o cliente pode falhar tentando ler algo que nunca foi enviado.

Forma mais segura:

if (response.status === 204) {
  return null;
}

return await response.json();

O programador COBOL compreenderá imediatamente.

É como um programa que termina com RETURN-CODE = 0, mas não gera relatório porque não havia nada a imprimir.


A terceira família: 3xx — o caminho mudou

Os códigos 3xx indicam redirecionamento, reutilização de cache ou mudança de localização.

O servidor não está necessariamente dizendo que existe um erro.

Ele pode estar dizendo:

“Aquilo que você procura está em outro lugar.”


301 Moved Permanently

O recurso mudou definitivamente.

Exemplo:

GET /api/v1/clientes

Resposta:

HTTP/1.1 301 Moved Permanently
Location: /api/v2/clientes

A antiga rota foi substituída.

Isso pode ocorrer por:

  • mudança de domínio;

  • migração para HTTPS;

  • nova versão da API;

  • reestruturação de endpoints;

  • alteração permanente de endereço.

O erro aparece quando o cliente não segue redirecionamentos automaticamente.

O navegador geralmente segue.

Uma aplicação antiga talvez não.

Um programa batch escrito quando televisores ainda possuíam madeira nas laterais pode simplesmente receber o 301 e ficar olhando para ele como um discípulo diante de uma porta fechada.


302 Found

O 302 representa normalmente um redirecionamento temporário.

Um caso comum é autenticação.

Você chama:

GET /api/clientes

O servidor responde:

HTTP/1.1 302 Found
Location: /login

O navegador segue o redirecionamento e recebe:

HTTP/1.1 200 OK
Content-Type: text/html

Então o desenvolvedor reclama:

“A API está retornando HTML em vez de JSON!”

Na realidade, a API redirecionou para a página de login, e o cliente seguiu automaticamente.

A sequência real foi:

GET /api/clientes
        ↓
302 /login
        ↓
200 página HTML

Por isso, ferramentas como curl ajudam muito.

curl -v https://api.exemplo.com/clientes

O modo verboso revela os passos intermediários.


304 Not Modified

O 304 está relacionado a cache.

Ele significa:

“O conteúdo não mudou. Use a cópia que você já possui.”

Primeira requisição:

GET /imagem.png

Resposta:

HTTP/1.1 200 OK
ETag: "abc123"

Requisição posterior:

GET /imagem.png
If-None-Match: "abc123"

Resposta:

HTTP/1.1 304 Not Modified

O servidor não envia novamente o arquivo.

O navegador usa a versão em cache.

Isso economiza:

  • banda;

  • tempo;

  • processamento;

  • custo;

  • tráfego.

Mas também pode criar o famoso bug fantasma:

“Eu alterei o JavaScript, mas o navegador insiste em executar a versão antiga.”

Nesse momento, o culpado pode ser:

Cache-Control
ETag
CDN
Proxy
Service Worker
Cache do navegador

O jovem programador apaga a aplicação inteira.

O mestre apenas pressiona Ctrl + Shift + R.


A quarta família: 4xx — a requisição chegou com problemas

Os códigos 4xx indicam que existe algum impedimento associado à requisição do cliente.

Isso não significa que o frontend é culpado.

Pode haver documentação errada, configurações incorretas, permissões mal atribuídas ou contratos incompatíveis.

O código apenas indica onde começar.


400 Bad Request

O 400 significa requisição inválida.

Possíveis causas:

  • JSON malformado;

  • parâmetro incorreto;

  • data em formato inválido;

  • cabeçalho errado;

  • corpo incompleto;

  • tipo de conteúdo incompatível.

Exemplo:

{
  "nome": "Vagner",
  "idade": 52,
}

A vírgula final pode tornar o JSON inválido.

Outro exemplo:

Content-Type: text/plain

quando a API espera:

Content-Type: application/json

Analogia COBOL:

05 WS-DATA PIC 9(8).

Entrada recebida:

23/07/2026

O humano compreende.

O programa não.

O layout esperava oito dígitos, talvez:

20260723

Quando receber 400, verifique:

Método
URL
Query string
Headers
Content-Type
JSON
Tipos
Datas
Campos obrigatórios
Codificação

401 Unauthorized

O 401 indica problema de autenticação.

Tradução prática:

“Não consegui validar corretamente quem você é.”

Causas comuns:

  • token ausente;

  • token expirado;

  • token inválido;

  • chave de API incorreta;

  • assinatura inválida;

  • usuário inexistente;

  • relógio fora de sincronia.

Exemplo:

Authorization: Bearer token-expirado

Resposta:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

Uma situação curiosa ocorre com tokens JWT.

O token pode possuir:

Data de emissão
Data de expiração
Emissor
Audiência
Escopos
Assinatura

Se o relógio da máquina cliente estiver alguns minutos errado, um token válido pode parecer expirado ou ainda não válido.

Às vezes o grande vilão da autenticação não é um hacker internacional.

É o relógio do servidor.


403 Forbidden

O 403 significa que a identidade pode ser conhecida, mas a operação não é permitida.

Diferença essencial:

401 = não consegui autenticar você
403 = autentiquei você, mas você não possui autorização

Exemplo:

Usuário: Vagner
Perfil: CONSULTA
Operação: DELETE

Resposta:

HTTP/1.1 403 Forbidden

No mundo mainframe, pense em RACF:

Usuário reconhecido
Senha aceita
Acesso ao recurso negado

Você entrou no prédio.

Possui crachá.

Mas a porta da sala de produção continua fechada.

E o segurança não parece disposto a discutir filosofia.


404 Not Found

O 404 significa que a rota ou o recurso não foi encontrado.

Pode ser:

URL errada
Endpoint inexistente
ID inexistente
Versão incorreta
Ambiente errado
Deploy incompleto
Maiúscula ou minúscula diferente
Context path ausente

Exemplo:

GET /clientes/999999

Resposta:

HTTP/1.1 404 Not Found

Existem duas situações diferentes.

A rota não existe

/api/clientez/123

O endpoint foi digitado incorretamente.

O recurso não existe

/api/clientes/999999

O endpoint existe, mas o cliente não.

Outra armadilha:

O endpoint existe em desenvolvimento:

/api/v2/clientes

Mas produção só possui:

/api/v1/clientes

O código está no repositório.

O pipeline ficou verde.

A apresentação para a diretoria foi magnífica.

O endpoint, entretanto, não foi implantado.

O 404 está apenas dizendo:

“Aqui, neste ambiente, nesta rota, isso não existe.”


405 Method Not Allowed

A rota existe, mas o método HTTP não é permitido.

Exemplo:

POST /clientes/123

Resposta:

HTTP/1.1 405 Method Not Allowed
Allow: GET, PUT, DELETE

Diferença:

404 = não encontrei a rota ou o recurso
405 = encontrei a rota, mas esse verbo não é aceito

É como chegar à agência correta, falar com a pessoa correta e pedir a operação errada.


409 Conflict

O 409 indica conflito com o estado atual do recurso.

Exemplos:

  • usuário duplicado;

  • e-mail já cadastrado;

  • versão antiga do registro;

  • assento já reservado;

  • pedido já processado;

  • recurso sendo alterado por outro processo.

Imagine:

Cliente A lê:

{
  "id": 100,
  "saldo": 500,
  "versao": 7
}

Cliente B altera o registro.

Agora a versão é 8.

Cliente A tenta salvar usando a versão 7.

Resposta:

HTTP/1.1 409 Conflict

A requisição é válida.

O problema é que ela nasceu em um passado que já não existe.

É praticamente uma viagem no tempo corporativa.


415 Unsupported Media Type

O formato enviado não é aceito.

Você envia:

Content-Type: application/xml

Mas a API aceita apenas:

Content-Type: application/json

Resposta:

HTTP/1.1 415 Unsupported Media Type

Antes de investigar o banco de dados, examine o cabeçalho.

Muitos incidentes terminam com uma frase humilhante:

“Estávamos enviando XML para um endpoint JSON.”


422 Unprocessable Content

O JSON está bem formado, mas os dados não passam nas regras.

Exemplo:

{
  "nome": "Ana",
  "idade": -17,
  "email": "banana"
}

A sintaxe é válida.

Os valores não são.

Resposta:

HTTP/1.1 422 Unprocessable Content

{
  "errors": [
    {
      "field": "idade",
      "message": "Valor inválido"
    },
    {
      "field": "email",
      "message": "Formato inválido"
    }
  ]
}

Distinção prática:

400 = não consegui interpretar corretamente
422 = interpretei, mas não posso aceitar

Nem todas as APIs seguem essa divisão, mas ela é útil.


429 Too Many Requests

O cliente ultrapassou o limite de requisições.

Resposta:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

Tradução:

“Pare por sessenta segundos.”

O cliente mal projetado interpreta:

“Tente imediatamente mais quinhentas vezes.”

E assim nasce um pequeno ataque de negação de serviço produzido pela própria aplicação.

A solução correta inclui:

  • respeitar Retry-After;

  • usar backoff exponencial;

  • adicionar jitter;

  • reduzir concorrência;

  • usar cache;

  • evitar polling excessivo.

Exemplo:

1ª falha → espera 1 segundo
2ª falha → espera 2 segundos
3ª falha → espera 4 segundos
4ª falha → espera 8 segundos

Com jitter, adiciona-se um pequeno intervalo aleatório.

Isso evita que milhares de clientes voltem exatamente ao mesmo tempo, como discípulos famintos quando alguém anuncia que o café está pronto.


A quinta família: 5xx — o servidor tropeçou

Os códigos 5xx indicam falha do lado servidor ou de alguma infraestrutura associada.

Mas cuidado:

Uma requisição específica pode acionar um bug do servidor.

O cliente pode ser o gatilho, embora a responsabilidade técnica continue sendo da aplicação.


500 Internal Server Error

É o erro genérico.

Pode representar:

  • exceção não tratada;

  • variável nula;

  • banco indisponível;

  • configuração incorreta;

  • falha de serialização;

  • falta de memória;

  • arquivo ausente;

  • erro de programação;

  • dependência indisponível.

Resposta ruim:

HTTP/1.1 500 Internal Server Error

Something went wrong

Resposta melhor:

HTTP/1.1 500 Internal Server Error
X-Correlation-ID: A7C9-2218

{
  "status": 500,
  "message": "Não foi possível concluir a operação",
  "correlationId": "A7C9-2218"
}

O correlation ID é extremamente importante.

Ele permite localizar a mesma transação nos logs de:

Gateway
Aplicação
Banco
Fila
Mainframe
Serviço externo

O usuário não deve receber stack trace, senha, SQL completo ou detalhes internos.

Isso seria como imprimir o conteúdo do dump de produção na porta da empresa.


502 Bad Gateway

Um gateway ou proxy recebeu uma resposta inválida do servidor posterior.

Fluxo:

Cliente
   ↓
Gateway
   ↓
Backend

O gateway está ativo.

O backend falhou, respondeu de forma inválida ou não aceitou a conexão.

Causas:

  • serviço caiu;

  • DNS interno falhou;

  • porta errada;

  • certificado inválido;

  • container reiniciando;

  • conexão recusada;

  • resposta malformada.

Tradução kung fu:

O mensageiro chegou ao portão, mas o mestre do templo não respondeu corretamente.


503 Service Unavailable

O serviço está temporariamente indisponível.

Possíveis causas:

  • manutenção;

  • sobrecarga;

  • nenhuma instância saudável;

  • aplicação iniciando;

  • pool de conexões esgotado;

  • circuit breaker aberto;

  • banco fora do ar.

Resposta:

HTTP/1.1 503 Service Unavailable
Retry-After: 120

Diferença:

500 = ocorreu uma falha interna inesperada
503 = o serviço não consegue atender agora

Em ambiente com containers, um 503 pode significar:

Load balancer funcionando
Nenhum pod saudável disponível

O restaurante está aberto.

A cozinha desapareceu.


504 Gateway Timeout

O gateway esperou pelo backend, mas o tempo limite expirou.

Fluxo:

Cliente
   ↓
Gateway
   ↓
API
   ↓
Banco
   ↓
Mainframe

O gateway espera 30 segundos.

O backend demora 45.

Resultado:

HTTP/1.1 504 Gateway Timeout

O detalhe mais valioso pode ser o tempo.

Se o erro ocorre sempre em exatamente 30 segundos, existe grande chance de um timeout configurado nessa camada.

Por exemplo:

Gateway timeout: 30 s
API timeout: 60 s
Banco responde em 42 s

A aplicação ainda trabalha quando o gateway abandona a conversa.

A solução não é automaticamente aumentar o timeout.

Talvez seja melhor:

  • otimizar SQL;

  • criar processamento assíncrono;

  • devolver 202;

  • usar fila;

  • paginar;

  • criar cache;

  • dividir o trabalho.

Aumentar o timeout sem investigar é como ensinar o discípulo a esperar mais tempo diante de uma porta emperrada.


O perigo dos retries

Nem toda chamada deve ser repetida.

Métodos normalmente idempotentes

GET
PUT
DELETE

Em princípio, repetir deve conduzir ao mesmo estado final.

POST normalmente não é idempotente

Exemplo:

POST /pagamentos

O servidor processa o pagamento.

A resposta demora.

O gateway devolve 504.

O cliente repete.

Resultado possível:

Pagamento 1 criado
Pagamento 2 criado
Cliente furioso
Reunião extraordinária
PowerPoint com 74 slides

Para evitar duplicidade, APIs podem aceitar:

Idempotency-Key: pedido-82719-pagamento-1

Se a mesma operação for repetida, o servidor reconhece a chave.

Retries fazem mais sentido em códigos como:

408
429
502
503
504

Mesmo assim, devem possuir:

  • limite de tentativas;

  • backoff;

  • jitter;

  • controle de duplicidade;

  • respeito ao Retry-After.

Não repita cegamente:

400
401
403
404
409
422

Uma requisição errada repetida cem vezes continua errada.

Ela apenas fica mais barulhenta.


Passo a passo para investigar uma API

Quando surgir um erro, siga esta ordem.

Passo 1 — veja o método

GET
POST
PUT
PATCH
DELETE

A rota pode aceitar apenas alguns métodos.

Passo 2 — confira a URL completa

Verifique:

Protocolo
Domínio
Porta
Context path
Versão
Endpoint
Query string
Barra final
Maiúsculas e minúsculas

Passo 3 — leia o status

Classifique:

1xx → continuação
2xx → sucesso
3xx → redirecionamento ou cache
4xx → problema associado à requisição
5xx → problema no servidor ou infraestrutura

Passo 4 — leia os headers

Especialmente:

Authorization
Content-Type
Accept
Location
Retry-After
ETag
X-Correlation-ID

Passo 5 — leia o corpo

A mensagem pode indicar:

Campo inválido
Token expirado
Recurso ausente
Versão conflitante
Limite excedido

Passo 6 — observe o tempo

Erro em 10 ms → falha imediata
Erro em 30 s exatos → timeout provável
Erro variável → dependência instável

Passo 7 — procure o correlation ID

Use-o nos logs.

Passo 8 — reproduza com ferramenta simples

Exemplo:

curl -v \
  -H "Authorization: Bearer TOKEN" \
  -H "Accept: application/json" \
  https://api.exemplo.com/clientes/123

O curl -v mostra:

  • conexão;

  • certificados;

  • headers enviados;

  • headers recebidos;

  • redirecionamentos;

  • status;

  • detalhes úteis.

Passo 9 — só então abra os logs

Os logs não devem ser o primeiro lugar.

Devem ser o lugar correto após o status indicar a direção.


O algoritmo COBOL do guerreiro HTTP

Um programador COBOL pode pensar desta forma:

EVALUATE TRUE

   WHEN HTTP-STATUS >= 100
    AND HTTP-STATUS < 200
      DISPLAY 'RESPOSTA INFORMATIVA'

   WHEN HTTP-STATUS >= 200
    AND HTTP-STATUS < 300
      DISPLAY 'SUCESSO HTTP'
      PERFORM VALIDAR-RESULTADO-FUNCIONAL

   WHEN HTTP-STATUS >= 300
    AND HTTP-STATUS < 400
      DISPLAY 'VERIFICAR REDIRECT OU CACHE'
      PERFORM ANALISAR-LOCATION

   WHEN HTTP-STATUS >= 400
    AND HTTP-STATUS < 500
      DISPLAY 'VERIFICAR REQUEST'
      PERFORM ANALISAR-AUTH
      PERFORM ANALISAR-HEADERS
      PERFORM ANALISAR-BODY

   WHEN HTTP-STATUS >= 500
    AND HTTP-STATUS < 600
      DISPLAY 'VERIFICAR SERVIDOR'
      PERFORM LOCALIZAR-CORRELATION-ID
      PERFORM CONSULTAR-LOGS

   WHEN OTHER
      DISPLAY 'STATUS INESPERADO'

END-EVALUATE.

Mas o mestre acrescentaria:

IF HTTP-STATUS = 200
   AND BUSINESS-RESULT NOT = 'SUCCESS'
      DISPLAY 'HTTP OK, NEGOCIO NAO OK'
END-IF.

Porque o sábio sabe que nem todo 200 representa felicidade.


Curiosidades do templo HTTP

Curiosidade 1 — 401 possui um nome confuso

401 Unauthorized é usado principalmente para falha de autenticação.

O código mais associado à falta de autorização é 403.

O nome histórico permaneceu, e agora gera confusão em várias gerações de desenvolvedores.

Curiosidade 2 — 404 pode proteger informações

Alguns sistemas devolvem 404 em vez de 403 para não revelar que determinado recurso existe.

Em vez de dizer:

“Existe, mas você não pode acessar.”

o sistema responde:

“Nunca ouvi falar.”

É o equivalente digital do monge que esconde o pergaminho atrás das costas.

Curiosidade 3 — 418 existe como brincadeira

O código 418 I’m a Teapot nasceu como uma piada relacionada a um protocolo fictício de controle de bules de café.

Não deve ser usado como erro sério de produção.

Embora, em certas empresas, talvez descreva com precisão a maturidade da arquitetura.

Curiosidade 4 — 200 pode esconder desastre

Algumas APIs antigas retornam 200 para tudo.

Exemplo:

{
  "status": "ERROR",
  "message": "Database unavailable"
}

Isso dificulta:

  • monitoramento;

  • alertas;

  • métricas;

  • retries;

  • tratamento automático.

O protocolo foi criado para comunicar semântica.

Ignorá-lo é como comprar um painel de instrumentos e cobrir todos os indicadores com fita adesiva.

Curiosidade 5 — o tempo é um código invisível

Um 500 em 5 milissegundos e um 500 em 60 segundos provavelmente possuem causas diferentes.

O tempo de resposta é quase um segundo status.


Easter egg: o mestre e o código 404

Conta-se que um jovem discípulo passou três dias procurando um endpoint.

Ele verificou:

  • banco de dados;

  • certificados;

  • filas;

  • firewall;

  • mainframe;

  • memória;

  • CPU;

  • logs;

  • DNS;

  • fases da lua.

Ao final, o mestre perguntou:

— Qual URL você chamou?

O discípulo respondeu:

/api/v1/cilentes

O mestre permaneceu em silêncio.

O discípulo percebeu a troca de letras.

Perguntou:

— Por que não me avisou antes?

O mestre respondeu:

— Eu avisei.

— Quando?

— No primeiro 404.

Naquela noite, o discípulo aprendeu duas lições:

  1. O servidor fala.

  2. O ego do desenvolvedor nem sempre escuta.


A regra final do Bellacosa Mainframe

Guarde este mapa:

1xx → continue observando
2xx → confirme o resultado
3xx → siga o caminho
4xx → revise a requisição
5xx → investigue o servidor

Depois aprofunde:

Status
+ método
+ URL
+ headers
+ body
+ duração
+ correlation ID
= diagnóstico

O código HTTP não é a solução completa.

Ele é a primeira pista.

Ele não diz necessariamente qual linha falhou, qual tabela travou ou qual container decidiu abandonar esta dimensão.

Mas reduz o universo de possibilidades.

Em vez de perguntar:

“O que pode estar errado em toda a arquitetura?”

você pergunta:

“Por que este cliente recebeu um 401?”

ou:

“Qual upstream provocou este 502?”

ou:

“Por que a chamada sempre termina em 504 após 30 segundos?”

A pergunta fica menor.

A investigação fica objetiva.

O incidente deixa de ser uma lenda oriental contada por desenvolvedores apavorados ao redor de um monitor.

E torna-se engenharia.

No último episódio, o jovem programador recebeu uma nova mensagem:

HTTP/1.1 403 Forbidden

A equipe começou a correr.

Um administrador abriu os logs.

Outro reiniciou o servidor.

Alguém sugeriu aumentar a memória.

Um consultor propôs migrar tudo para Kubernetes.

O jovem permaneceu sentado.

Tomou um gole de café.

Abriu o token.

Verificou os escopos.

Descobriu que o usuário possuía permissão de leitura, mas não de exclusão.

Corrigiu a autorização.

A chamada retornou:

HTTP/1.1 204 No Content

O velho mestre observou de longe e perguntou:

— O que a API disse?

O programador respondeu:

— Nada.

O mestre sorriu.

— Então finalmente funcionou.

Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...