☕ 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

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.

☕ Gostou deste café?
Siga o Bellacosa Mainframe e acompanhe os próximos artigos.
SEGUIR O BLOG

Sem comentários:

Enviar um comentário

De Fã para Fã. Conteúdo não oficial produzido como homenagem, comentário, análise ou paródia. Personagens, marcas e obras eventualmente mencionados pertencem aos seus respectivos titulares.
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...