☕ 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 API Testing. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta API Testing. Mostrar todas as mensagens

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.

quarta-feira, 8 de setembro de 2021

📚 EINA TULLE E O GRIMÓRIO QUE ENSINOU O COBOL A FALAR REST

  

Bellacosa Mainframe apresenta o Swagger

☕ Um Café no Bellacosa Mainframe

📚 EINA TULLE E O GRIMÓRIO QUE ENSINOU O COBOL A FALAR REST

Swagger, OpenAPI, REST, HTTP, JSON, YAML, APIs, contratos, Swagger UI, autenticação, OAuth, JWT, RACF, CICS, IMS, Db2, VSAM, z/OS Connect, CI/CD, observabilidade — e o dia em que um programador COBOL descobriu que 200 OK não significava que a aventura havia terminado.

Sob a tutela de Eina Tulle, de Is It Wrong to Try to Pick Up Girls in a Dungeon?



🎬 PRÓLOGO — BEM-VINDO À GUILDA, AVENTUREIRO

Imagine um jovem programador COBOL chegando para seu primeiro dia em uma grande empresa.

Ele conhece algumas coisas:

IDENTIFICATION DIVISION.
PROGRAM-ID. CONSULTA.

DATA DIVISION.
WORKING-STORAGE SECTION.

01 WS-CLIENTE.
   05 WS-ID       PIC 9(09).
   05 WS-NOME     PIC X(40).

JCL ele está começando a entender.

Já ouviu falar de CICS.

Db2 ainda parece uma dungeon particularmente perigosa.

E então alguém aparece e diz:

— Precisamos criar uma API REST usando OpenAPI.

Nosso aventureiro olha para a tela como Bell Cranel provavelmente olharia para uma criatura vários níveis acima do seu.

API? REST? Swagger? OpenAPI? JSON?

É nesse momento que Eina Tulle empurra seus óculos, abre uma enorme pilha de documentos sobre a mesa da Guilda e responde:

— Antes de entrar na Dungeon, você precisa conhecer o mapa.

E talvez essa seja a melhor definição inicial de OpenAPI para um programador COBOL.

OpenAPI é parte do mapa.

Não é o monstro.

Não é a espada.

Não é o aventureiro.

É uma descrição formal de como encontrar e utilizar aquilo que existe do outro lado da porta.

E essa porta pode terminar justamente em um programa COBOL.



📜 CAPÍTULO 1 — QUANDO NASCEU O SWAGGER?

Nossa história começa muito depois do nascimento do COBOL.

COBOL surgiu em 1959.

CICS apareceu no final da década de 1960.

Db2 chegou comercialmente na década de 1980.

Swagger é praticamente uma criança perto deles.

A especificação Swagger foi criada na Wordnik em 2010 e publicada como projeto open source no ano seguinte. Em 2015, os direitos do projeto foram adquiridos pela SmartBear; naquele mesmo ano, a especificação foi doada para a recém-formada OpenAPI Initiative, sob a Linux Foundation. O Swagger 2.0 tornou-se a base do que passou a ser chamado de OpenAPI Specification. (OpenAPI Initiative)

Portanto:

1959       COBOL
  │
1969       CICS
  │
1980s      Db2
  │
2010       Swagger nasce
  │
2011       projeto/spec é publicado como open source
  │
2015       OpenAPI Initiative
  │
2017       OpenAPI 3.0
  │
2025       OpenAPI 3.2

Em setembro de 2025 foi publicada a especificação OpenAPI 3.2.0. (OpenAPI Initiative Publications)

Curiosamente, enquanto escrevemos em 2026, a página oficial de versões já lista também a 3.2.1. (OpenAPI Initiative Publications)

Mas aqui existe uma regra importantíssima para quem trabalha com mainframe:

A versão mais recente de um padrão não significa automaticamente a versão suportada por cada produto da sua arquitetura.

O IBM z/OS Connect, por exemplo, documenta seus próprios níveis suportados de OpenAPI. Portanto, consulte a matriz do produto antes de simplesmente colocar a versão mais nova no projeto.

Eina escreveria isso no topo da ficha do aventureiro:

Conheça a Dungeon antes de comprar a espada.



🧩 CAPÍTULO 2 — SWAGGER NÃO É OPENAPI

Esta é provavelmente a confusão mais comum.

Durante muito tempo Swagger era tanto o nome da especificação quanto do ecossistema.

Depois da criação da OpenAPI Initiative, houve uma separação conceitual.

Hoje podemos pensar:

OPENAPI
     ↓
ESPECIFICAÇÃO / CONTRATO

SWAGGER
     ↓
FERRAMENTAS / ECOSSISTEMA

A OpenAPI Specification é uma descrição padronizada e independente de linguagem para APIs HTTP. Ela permite que pessoas e programas descubram as capacidades de um serviço sem precisar examinar seu código-fonte. (OpenAPI Initiative Publications)

Já no universo Swagger encontramos ferramentas para trabalhar com esse contrato.

Por exemplo:

Swagger UI
Swagger Editor
Swagger Codegen

Então grave:

OpenAPI descreve. Swagger ajuda você a trabalhar com essa descrição.

Não diga simplesmente:

“Swagger é uma API.”

Não é.



📖 CAPÍTULO 3 — OPENAPI É O COPYBOOK DA FRONTEIRA?

Eina provavelmente faria uma analogia para nosso aprendiz COBOL.

Considere:

01 CLIENTE-REQUEST.
   05 CLIENTE-ID       PIC 9(09).

01 CLIENTE-RESPONSE.
   05 CLIENTE-NOME     PIC X(40).
   05 CLIENTE-STATUS   PIC X(01).
   05 CLIENTE-LIMITE   PIC S9(9)V99 COMP-3.

Um programador COBOL imediatamente reconhece que existe uma estrutura.

Agora observe uma representação externa:

Cliente:
  type: object
  properties:
    id:
      type: integer
    nome:
      type: string
    status:
      type: string
    limite:
      type: number

A semelhança conceitual ajuda.

Mas cuidado.

OpenAPI não é literalmente um COPYBOOK moderno.

OpenAPI consegue descrever muito mais sobre a interface HTTP:

URL
paths
operações
parâmetros
headers
request
response
schemas
autenticação
status codes

Podemos dizer didaticamente:

COPYBOOK
   ↓
estrutura utilizada pelo programa

OPENAPI
   ↓
contrato da interface HTTP

O COPYBOOK pode dizer como o COBOL enxerga determinado dado.

OpenAPI pode dizer como o mundo exterior conversa com o serviço.


🌐 CAPÍTULO 4 — A PORTA DA DUNGEON CHAMA-SE ENDPOINT

Suponha:

GET /api/clientes/101?page=2

Temos diferentes componentes:

GET                 HTTP METHOD

/api/clientes       PATH

101                 PATH PARAMETER

page=2              QUERY PARAMETER

O path parameter normalmente participa da identificação do recurso.

Exemplo:

/clientes/101
/clientes/102
/clientes/103

Já query parameters frequentemente aparecem em filtros, paginação, ordenação etc.:

/clientes?page=2

/clientes?cidade=Itatiba

/clientes?status=ativo&sort=nome

Para quem veio do COBOL, não há magia nisso.

Estamos simplesmente recebendo dados através de outra interface.


🏰 CAPÍTULO 5 — MAS COMO ISSO CHEGA AO MAINFRAME?

Agora entramos na parte divertida.

Imagine:

MOBILE
   │
   │ HTTPS / JSON
   ▼
API GATEWAY
   │
   ▼
z/OS CONNECT
   │
   ▼
CICS
   │
   ▼
COBOL
   │
   ├────────► Db2
   │
   └────────► VSAM

O programa COBOL não precisa transformar-se magicamente em JavaScript.

O IBM z/OS Connect pode atuar como uma camada entre APIs REST e recursos z/OS. A documentação da IBM descreve API providers capazes de transformar requisições REST em chamadas aos subsistemas z/OS e converter dados entre JSON e estruturas nativas consumíveis por COBOL, PL/I e C. (IBM)

Isso é extraordinariamente importante.

Externamente alguém manda:

{
  "clienteId": 101
}

Internamente podemos terminar com algo semelhante a:

01 CLIENTE-REQUEST.
   05 CLIENTE-ID PIC 9(09).

A interface moderna não precisa destruir o legado.

Ela pode encapsulá-lo.


🧙 CAPÍTULO 6 — O GRIMÓRIO OPENAPI

Vamos imaginar uma API:

GET /clientes/{id}

Podemos ter uma descrição OpenAPI simplificada:

openapi: 3.0.3

info:
  title: Cliente API
  version: 1.0.0

paths:
  /clientes/{id}:
    get:
      summary: Consulta cliente
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Cliente encontrado
        '404':
          description: Cliente não encontrado

Eina apontaria para isso e perguntaria:

— Onde está o COBOL?

Não está.

E esse é justamente o ponto.

O consumidor não precisa saber se atrás da API temos:

COBOL
Java
Python
CICS
IMS
Db2
VSAM
um microsserviço
ou três kobolds digitando cartões perfurados.

Ele conhece o contrato.

Isso é desacoplamento.


🖥️ CAPÍTULO 7 — SWAGGER UI É O QUADRO DE MISSÕES DA GUILDA

Agora pegamos aquele contrato e apresentamos através de uma interface.

Entra o Swagger UI.

O desenvolvedor consegue explorar coisas como:

GET /clientes/{id}

POST /clientes

PUT /clientes/{id}

DELETE /clientes/{id}

Ele pode encontrar o endpoint, observar parâmetros, analisar schemas e, quando habilitado, executar chamadas diretamente.

O fluxo apresentado nas imagens é muito didático:

OPEN SWAGGER UI
       ↓
FIND ENDPOINT
       ↓
TRY IT OUT
       ↓
ENTER PARAMETERS
       ↓
EXECUTE
       ↓
INSPECT RESPONSE
       ↓
VALIDATE

Excelente para exploração.

Mas existe uma armadilha.

Swagger UI não substitui uma estratégia completa de QA.


💚 CAPÍTULO 8 — O TERRÍVEL MONSTRO VERDE: 200 OK

Nosso aventureiro executa:

GET /clientes/101

Swagger fica feliz:

200 OK

Ele comemora.

Eina bate o livro na mesa.

— Ainda não.

Porque 200 OK diz algo sobre o resultado da requisição HTTP.

Não prova automaticamente que a regra de negócio está correta.

Imagine:

{
  "cliente": 101,
  "saldo": 1000000.00
}

O saldo real era:

1000.00

Tecnicamente:

HTTP       OK
JSON       OK
SCHEMA     OK
NEGÓCIO    ERRADO

Isso deveria soar familiar para qualquer mainframer.

É o equivalente a:

MAXCC=0000

e descobrir depois que o arquivo de saída continha valores incorretos.

RC=0 não é sinônimo de negócio correto.

HTTP 200 também não.


🧪 CAPÍTULO 9 — O QA PRECISA DESCER MAIS ANDARES

Teste pelo menos:

status HTTP
response body
headers
campos obrigatórios
tipos
schema
valores-limite
dados inválidos
autenticação
autorização
timeout
concorrência
idempotência
rollback
indisponibilidade do backend
performance

Suponha:

POST /pagamentos

Cliente envia:

{
   "conta": "12345",
   "valor": 100
}

O backend processa.

Mas ocorre timeout antes de o cliente receber a resposta.

Ele tenta novamente.

Se não houver desenho adequado:

REQUEST 1 → DEBITA R$100

TIMEOUT

REQUEST 2 → DEBITA R$100

Swagger pode estar perfeitamente configurado.

OpenAPI pode estar impecável.

E você acabou de cobrar o cliente duas vezes.

Bem-vindo ao andar onde moram os monstros de verdade.


⚛️ CAPÍTULO 10 — REST NÃO MATOU ACID

Por trás de:

POST /transferencias

pode existir:

UPDATE CONTA A
      ↓
UPDATE CONTA B
      ↓
COMMIT

Se algo falhar:

ROLLBACK

Portanto:

REST
 ↓
JSON
 ↓
z/OS Connect
 ↓
CICS
 ↓
COBOL
 ↓
Db2
 ↓
LOCKS
 ↓
LOG
 ↓
COMMIT / ROLLBACK

A modernização da interface não aboliu cinquenta anos de engenharia transacional.

Isso é uma das coisas mais importantes para um iniciante entender.

API é a porta da Dungeon.

Não é a Dungeon inteira.


🔐 CAPÍTULO 11 — “QUEM É VOCÊ?” E “O QUE VOCÊ PODE FAZER?”

Outra imagem traz uma distinção excelente:

AUTHENTICATION
Quem é você?

AUTHORIZATION
O que você pode fazer?

Podemos encontrar mecanismos como:

Basic Authentication
API Key
Bearer Token
JWT
OAuth 2.0

Agora transporte isso para IBM Z:

APP
 │
 ▼
OAuth / OIDC
 │
 ▼
TOKEN
 │
 ▼
API GATEWAY
 │
 ▼
z/OS Connect
 │
 ▼
SAF / RACF
 │
 ▼
CICS
 │
 ▼
COBOL

Surge uma pergunta arquitetural fundamental:

Qual identidade chega ao recurso protegido?

Porque autenticar alguém na primeira porta não significa automaticamente permitir qualquer operação atrás dela.

É justamente daí que nasce a distinção didática entre:

401
problema de autenticação/credenciais

403
identidade reconhecida,
mas acesso não permitido

A própria oferta atual do z/OS Connect destaca autorização granular por operação para serviços de negócio. (IBM)


🚨 CAPÍTULO 12 — NÃO MANDE SQLCODE -911 PARA O CLIENTE

Imagine:

EXEC SQL
   SELECT SALDO
     INTO :WS-SALDO
     FROM CONTA
    WHERE ID = :WS-ID
END-EXEC

Alguma condição ocorre no Db2.

Você não deveria transformar automaticamente sua implementação interna em contrato público:

{
   "sqlcode": -911
}

Muito menos:

{
   "abend": "ASRA",
   "program": "XPTO1234"
}

Você está vazando detalhes da implementação.

O ideal é existir um mapeamento coerente entre erro interno e contrato externo.

Por exemplo:

Db2: registro inexistente
        ↓
regra da aplicação
        ↓
HTTP 404

Resposta:

{
   "code": "ACCOUNT_NOT_FOUND",
   "message": "Conta não encontrada"
}

Internamente você preserva informações suficientes para diagnóstico:

timestamp
transaction ID
correlation ID
program
CICS transaction
SQLCODE
trace
logs
SMF

O usuário recebe aquilo que precisa.

Operações recebe aquilo que precisa.

Segurança agradece.


🏗️ CAPÍTULO 13 — API-FIRST: DESENHE A MISSÃO ANTES DE ENTRAR NA DUNGEON

Aqui encontramos uma transformação particularmente interessante para equipes mainframe.

Tradicionalmente poderíamos imaginar:

COBOL
 ↓
interface
 ↓
documentação

API-first inverte parte desse raciocínio.

Primeiro definimos:

CONTRATO
 ↓
IMPLEMENTAÇÃO

Imagine:

POST /transferencias

Request:

{
   "origem": "123456",
   "destino": "987654",
   "valor": 250.00
}

Response:

{
   "transacao": "TRX829173",
   "status": "EFETIVADA"
}

Agora várias equipes podem trabalhar sobre o mesmo contrato:

           OpenAPI
              │
    ┌─────────┼──────────┐
    │         │          │
 Mobile      QA       Mainframe
    │         │          │
    ▼         ▼          ▼
 cliente    testes    implementação

E isso não é apenas teoria aplicada ao IBM Z. A IBM documenta desenvolvimento API-first no z/OS Connect usando documentos OpenAPI e ferramentas que geram artefatos de projeto e estruturas de linguagem necessárias à implementação, inclusive para aplicações CICS COBOL ou PL/I. (IBM)

A funcionalidade API-first foi introduzida no z/OS Connect 3.0.69. (IBM)

Para o COBOLzeiro, isso é enorme.

O contrato deixa de ser aquele PDF que alguém atualiza seis meses depois.

Ele passa a participar do processo de engenharia.


🔄 CAPÍTULO 14 — DO SWAGGER AO CI/CD

Agora podemos expandir o workflow apresentado nas imagens:

BUSINESS REQUIREMENT
          ↓
     API DESIGN
          ↓
   OPENAPI CONTRACT
          ↓
    CONTRACT REVIEW
          ↓
        MOCK
          ↓
   BACKEND DEVELOPMENT
          ↓
     z/OS CONNECT
          ↓
     CICS / IMS
          ↓
        COBOL
          ↓
    Db2 / VSAM
          ↓
 FUNCTIONAL TEST
          ↓
 NEGATIVE TEST
          ↓
 CONTRACT TEST
          ↓
 SECURITY TEST
          ↓
 PERFORMANCE TEST
          ↓
       CI/CD
          ↓
      DEPLOY
          ↓
    PRODUCTION

E isso destrói outro mito:

“DevOps não serve para mainframe.”

Serve.

O que muda são ferramentas, processos, controles e características da plataforma.


🔭 CAPÍTULO 15 — A AVENTURA NÃO TERMINA NO DEPLOY

Produção não é:

DEPLOY
  ↓
FIM

Produção é:

DEPLOY
  ↓
OBSERVAR
  ↓
MEDIR
  ↓
INVESTIGAR
  ↓
CORRIGIR

Por isso nosso desenho final começa a ganhar novas peças:

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

        ↘ TELEMETRIA
             ↓
        OBSERVABILIDADE

O z/OS Connect também oferece integração com mecanismos tradicionais do z/OS, incluindo rastreamento via SMF, e a linha atual oferece suporte a OpenTelemetry para observabilidade. (IBM)

Isso cria uma combinação particularmente poderosa:

OpenAPI
   =
O QUE FOI CONTRATADO

telemetria
   =
O QUE ESTÁ ACONTECENDO

Quando ambos se encontram, você deixa de simplesmente publicar APIs e começa a operá-las profissionalmente.


🗺️ CAPÍTULO 16 — O MAPA COMPLETO DA DUNGEON

Depois da aula de Eina, nosso jovem COBOLzeiro finalmente consegue desenhar:

                    CONSUMIDORES
                         │
               Web / Mobile / Cloud
                         │
                         ▼
                    HTTPS / REST
                         │
                         ▼
                 ┌───────────────┐
                 │ API CONTRACT  │
                 │    OpenAPI    │
                 └───────┬───────┘
                         │
                 Swagger UI
                         │
                         ▼
                    API GATEWAY
                         │
                   OAuth / JWT
                         │
                         ▼
                  z/OS CONNECT
                         │
           ┌─────────────┼─────────────┐
           │             │             │
           ▼             ▼             ▼
         CICS           IMS           Db2
           │             │
           ▼             ▼
         COBOL         COBOL
           │             │
           └──────┬──────┘
                  │
          ┌───────┼────────┐
          ▼       ▼        ▼
         Db2     VSAM     IMS DB
          │
          ▼
    COMMIT / ROLLBACK
          │
          ▼
    SMF / TELEMETRIA
          │
          ▼
    OBSERVABILIDADE

Agora Swagger deixou de parecer uma tecnologia alienígena.

É apenas mais uma peça da arquitetura.


💡 CAPÍTULO 17 — DEZ CONSELHOS DE EINA PARA O COBOLZEIRO

Antes de liberar nosso aventureiro para a Dungeon, Eina deixaria algumas regras no quadro da Guilda:

  1. Não confunda Swagger com OpenAPI. Um é o ecossistema de ferramentas; o outro é a especificação.

  2. Não trate Swagger UI como ferramenta completa de QA. Explorar endpoints é apenas o começo.

  3. Nunca comemore apenas porque recebeu 200 OK. Valide o negócio.

  4. Não exponha detalhes internos desnecessários. SQLCODE, ABEND e nomes internos não precisam virar sua interface pública.

  5. Teste erros deliberadamente. Token inválido, campo ausente, valor absurdo, backend indisponível e timeout também fazem parte da API.

  6. Pense em idempotência. Principalmente pagamentos e operações financeiras.

  7. Separe autenticação de autorização.

  8. Versione e governe o contrato. Alterar uma API usada por dezenas de consumidores é muito diferente de alterar uma rotina interna isolada.

  9. Use observabilidade desde o desenho. Não espere o primeiro incidente para perguntar como correlacionar uma requisição HTTP com o processamento z/OS.

  10. Não tente transformar COBOL em REST. Crie uma arquitetura em que REST e COBOL façam aquilo que cada tecnologia sabe fazer bem.


🥚 EASTER EGG — A REQUISIÇÃO DAS 03:17

Algumas semanas depois, produção recebe:

03:17:00.317

Uma chamada:

POST /transferencias

Swagger dizia:

201 Created

O dashboard estava verde.

CPU normal.

z/OS saudável.

CICS ativo.

Db2 ativo.

Nenhum grande alarme.

Mesmo assim, o cliente reclamava:

“Minha transferência apareceu duas vezes.”

Nosso jovem programador quase responde:

— Mas recebemos 201!

Ele para.

Lembra da aula.

Procura o correlation ID.

Segue a requisição.

API Gateway.

z/OS Connect.

CICS.

COBOL.

Db2.

COMMIT.

Depois encontra uma segunda requisição, enviada após um timeout do consumidor.

Mesmo payload.

Mesmo valor.

Outro processamento.

E então finalmente compreende a verdadeira lição daquela primeira aventura:

Disponibilidade não garante correção. HTTP correto não garante negócio correto. E observabilidade sem contexto é apenas uma coleção muito cara de luzes verdes.

No dia seguinte ele volta à Guilda.

Eina pergunta:

— Então, aprendeu Swagger?

Ele responde:

— Não.

Ela ergue uma sobrancelha.

— Aprendi sistemas.

Agora ela sorri.


☕ EPÍLOGO — O MAINFRAME NÃO PRECISA APRENDER A SER JOVEM

Existe uma narrativa recorrente na tecnologia:

velho
versus
novo

Mainframe versus cloud.

COBOL versus Java.

CICS versus microsserviços.

Batch versus APIs.

Essa oposição frequentemente é simplista.

Uma arquitetura moderna pode perfeitamente conter:

OpenAPI
Swagger
REST
JSON
OAuth
API Gateway
z/OS Connect
RACF
CICS
COBOL
Db2
VSAM
SMF
OpenTelemetry
CI/CD

Não existe contradição nisso.

Existe integração.

A aplicação mobile não precisa conhecer PIC, COMP-3, COMMAREA ou SQLCODE.

O programa COBOL não precisa conhecer detalhes da interface gráfica do smartphone.

Entre os dois existe um contrato.

OpenAPI.

E ferramentas como Swagger ajudam pessoas e máquinas a compreender e trabalhar com esse contrato.

O IBM z/OS Connect completa uma parte importantíssima dessa ponte, expondo recursos z/OS através de APIs e realizando transformações entre o universo REST/JSON e estruturas utilizadas pelas aplicações z/OS. (IBM)

Talvez seja essa a maior lição sob a tutela de Eina Tulle.

Ela jamais mandaria um aventureiro para a Dungeon simplesmente porque ele tinha uma espada nova.

Primeiro ensinaria:

o mapa
os níveis
os monstros
as regras
as rotas
os riscos
e como voltar vivo.

Swagger UI é uma ferramenta.

OpenAPI é um contrato.

REST é um estilo arquitetural.

HTTP é um protocolo.

JSON é uma representação de dados.

OAuth pode participar da segurança.

z/OS Connect pode fazer a ponte.

CICS pode administrar a transação.

COBOL pode executar a regra de negócio.

Db2 pode preservar os dados.

RACF/SAF pode participar da proteção.

SMF e OpenTelemetry podem ajudar a contar o que aconteceu.

Nenhuma dessas peças, sozinha, é “a modernização”.

A arquitetura aparece quando sabemos como todas elas se relacionam.

E é justamente por isso que talvez a pergunta mais interessante não seja:

“Como substituir COBOL por APIs?”

Mas:

“Como fazer décadas de lógica de negócio confiável participarem de um mundo orientado a APIs sem destruir aquilo que já funciona?”

Quando nosso jovem aventureiro consegue responder isso, ele já não está apenas aprendendo Swagger.

Ele começou a compreender o verdadeiro mapa da Dungeon chamada Enterprise Computing.

E em algum lugar, às 03:17, Eina Tulle fecha o último manual da Guilda e escreve na ficha do aventureiro:

LEVEL UP: COBOL PROGRAMMER → API-AWARE MAINFRAMER.

segunda-feira, 7 de outubro de 2019

🕯️ John Constantine e a API dos Condenados Requests, Responses, HTTP, JSON, autenticação, autorização, Test Data, ambientes, segurança, automação e aquele 200 OK

 

Bellacosa Mainframe e as APIs

☕ Um Café no Bellacosa Mainframe

🕯️ John Constantine e a API dos Condenados

Requests, Responses, HTTP, JSON, autenticação, autorização, Test Data, ambientes, segurança, automação e aquele 200 OK que jurava que estava tudo bem

Há uma regra que aprendi depois de muitos anos diante de terminais verdes, JCLs, CICS, dumps, arquivos VSAM e bancos de dados:

quando um sistema diz que está tudo bem depressa demais, comece a desconfiar.

John Constantine provavelmente concordaria.

Constantine não é exatamente o sujeito que você chama quando a torneira está vazando. Ele aparece quando a torneira começa a falar latim, o encanador desaparece e alguém encontra um pentagrama desenhado atrás da caixa-d'água.

Com APIs acontece algo semelhante.

Você manda:

GET /customers/42

e recebe:

HTTP/1.1 200 OK

O programador iniciante sorri.

Constantine acende um cigarro imaginário, olha para o monitor e pergunta:

— OK para quem?

Essa é a pergunta que guiará nossa investigação.

Porque uma API pode responder 200 OK enquanto devolve os dados errados. Pode autenticar João e entregar os registros de Maria. Pode registrar uma compra duas vezes. Pode diminuir o estoque três vezes. Pode devolver um CPF que jamais deveria estar naquela resposta.

E existe algo ainda mais diabólico.

Às vezes o sistema está certo...

...e o teste é que está errado.

Bem-vindo ao submundo de API Testing.



🕯️ CAPÍTULO 1 — O que diabos é uma API?

API significa:

Application Programming Interface.

Uma definição simples seria:

uma interface que permite que dois componentes de software se comuniquem seguindo regras previamente estabelecidas.

O exemplo clássico é o restaurante.

Temos:

CLIENTE
   ↓
GARÇOM
   ↓
COZINHA

O cliente não entra na cozinha para preparar o prato.

Ele faz um pedido.

O garçom leva esse pedido à cozinha.

A cozinha trabalha.

O garçom retorna com o resultado.

No mundo computacional:

APLICAÇÃO
    ↓
   API
    ↓
SERVIDOR

Uma aplicação meteorológica poderia solicitar:

GET /weather?city=Itatiba

e receber:

{
  "temp": 28,
  "condition": "Cloudy"
}

A aplicação não precisa saber como o servidor calculou aquilo.

Pode haver Python lá atrás.

Java.

Node.js.

Ou algo bem mais interessante para nós:

APP
 │
 ▼
REST API
 │
 ▼
API Gateway
 │
 ▼
z/OS Connect
 │
 ▼
CICS
 │
 ▼
COBOL
 │
 ├── Db2
 ├── VSAM
 ├── IMS
 └── MQ

Para quem chamou a API, isso deveria ser transparente.

Esse é o primeiro princípio importante:

a API oferece um contrato, não uma visita guiada à implementação.



🔮 CAPÍTULO 2 — O contrato

Constantine conhece contratos.

Normalmente os dele envolvem demônios, almas e cláusulas que ninguém deveria assinar sem ler as letras pequenas.

APIs também possuem contratos.

Se estabelecemos:

GET /users/42

podemos definir que a resposta bem-sucedida será:

200 OK
Content-Type: application/json

com:

{
  "id": 42,
  "name": "Asha",
  "active": true
}

Isso estabelece expectativas.

id deve existir.

id deve ser numérico.

name deve ser texto.

active deve ser booleano.

Portanto:

"id": 42

e:

"id": "42"

não são necessariamente equivalentes.

Um frontend permissivo talvez converta silenciosamente um para o outro.

O contrato não deveria depender dessa benevolência.

É justamente aí que entram schemas e especificações como OpenAPI: eles tornam parte dessas expectativas formalmente verificáveis.



🩸 CAPÍTULO 3 — Request e Response

Toda invocação começa com um pedido.

Por exemplo:

POST /users
Content-Type: application/json

Body:

{
  "name": "Asha",
  "role": "Tester"
}

O servidor poderia responder:

201 Created

e:

{
  "id": 42,
  "name": "Asha",
  "role": "Tester"
}

Temos então:

REQUEST
   ↓
API
   ↓
PROCESSAMENTO
   ↓
RESPONSE

O REQUEST é a pergunta.

O RESPONSE é a resposta.

Mas o investigador competente guarda ambos quando alguma coisa dá errado.

Porque perguntar:

"Por que a API falhou?"

sem saber exatamente qual request foi enviado é quase tão produtivo quanto perguntar a Constantine:

"Alguma coisa sobrenatural aconteceu ontem. Descubra."



🪦 CAPÍTULO 4 — Os cinco rituais HTTP

Os métodos mais comuns são:

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

Uma sequência CRUD poderia ser:

POST   /users
GET    /users/42
PATCH  /users/42
DELETE /users/42

Mas cuidado com uma simplificação comum.

HTTP não é CRUD.

Podemos perfeitamente encontrar:

POST /payments/123/capture

Nesse caso não estamos simplesmente dizendo "CREATE".

Estamos solicitando uma operação de negócio.

Existem ainda métodos como HEAD e OPTIONS, e os métodos permitidos também fazem parte da superfície que merece testes de segurança. A OWASP recomenda verificar métodos HTTP disponíveis e controles de acesso associados, inclusive tentando operações com métodos alternativos quando apropriado.



🚪 CAPÍTULO 5 — URL: o endereço da casa assombrada

Considere:

https://api.shop.com/v1/products/42?currency=BRL

Podemos desmontá-la:

https://api.shop.com
        │
        └── Base URL

/v1/products/42
        │
        └── endpoint/recurso

42
│
└── path parameter

currency=BRL
│
└── query parameter

E imediatamente surgem testes.

Produto existente:

42

Produto inexistente:

999999999

Valor estranho:

-1

Moeda válida:

BRL

Moeda inválida:

MORDOR

Campo ausente.

Campo vazio.

Valor enorme.

Caracteres especiais.

É aqui que o QA começa a se comportar como Constantine:

não pergunta somente o que deveria funcionar; pergunta também o que acontece quando alguém faz aquilo que não deveria.


🔑 CAPÍTULO 6 — Headers: símbolos desenhados na porta

Uma requisição pode carregar informações adicionais:

Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJ...
X-Request-ID: abc-123

Cada header possui uma função.

Content-Type informa o formato enviado.

Accept pode expressar o formato desejado.

Authorization transporta informações necessárias à autenticação/autorização conforme o mecanismo adotado.

E X-Request-ID, ou outro correlation ID equivalente, pode ser extremamente útil.

Imagine:

Browser
   ↓ abc-123
API Gateway
   ↓ abc-123
z/OS Connect
   ↓ abc-123
CICS
   ↓ abc-123
COBOL
   ↓ abc-123
MQ

Quando tudo explode às 03:17, você procura:

abc-123

e consegue reconstruir a passagem daquela transação pelos diversos componentes.

Nos sistemas distribuídos, correlação é praticamente trabalho de detetive.


👹 CAPÍTULO 7 — Os números da besta... HTTP

Não é exatamente 666.

Temos famílias:

1xx → informacional
2xx → sucesso
3xx → redirecionamento
4xx → problema relacionado à requisição/cliente
5xx → falha do lado servidor

Alguns velhos conhecidos:

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 existe uma distinção especialmente importante:

401 ≠ 403

Simplificando:

401 — você não está adequadamente autenticado.

403 — sabemos quem você é, mas você não pode fazer aquilo.

É a diferença entre Constantine chegar à porta sem a chave e chegar com a chave correta de uma sala para a qual ele continua não tendo autorização.


🧿 CAPÍTULO 8 — Authentication não é Authorization

Temos duas perguntas:

AUTHENTICATION
Quem é você?

AUTHORIZATION
O que você pode fazer?

Considere:

João → autenticado
Maria → autenticada

Isso não significa:

João → pode consultar dados privados de Maria

Teste:

GET /users/43
Authorization: Bearer TOKEN_DO_JOAO

Se 43 pertence a Maria e João não possui autorização para acessar aquele objeto, a aplicação precisa impedir o acesso.

Esse tipo de vulnerabilidade é importante o bastante para aparecer como Broken Object Level Authorization — BOLA no OWASP API Security Top 10.

O teste profissional, portanto, não pergunta apenas:

Tenho token?

Pergunta:

TOKEN A pode acessar RECURSO A?
TOKEN A pode acessar RECURSO B?
TOKEN B pode acessar RECURSO A?

USER pode executar operação ADMIN?
ADMIN pode?

GET é permitido?
DELETE também?
PATCH?

É uma matriz.

ATOR × RECURSO × AÇÃO

A OWASP descreve justamente esse modelo ator–recurso–ação como uma forma útil de representar e automatizar testes de autorização.


🧪 CAPÍTULO 9 — Positive, Negative e Boundary Testing

Suponha:

idade permitida = 18 até 60

Teste positivo:

25 → ACCEPT

Teste negativo:

"CONSTANTINE" → REJECT

Agora vêm os limites:

17
18
60
61

Por quê?

Porque um humilde:

IF WS-AGE > 18

em vez de:

IF WS-AGE >= 18

pode mandar o jovem de exatamente 18 anos diretamente para o purgatório da regra de negócio.

Os bugs adoram morar nas fronteiras.

Isso vale para:

quantidade
tamanho de senha
valor financeiro
número de itens
datas
paginação
strings
limites de crédito

Sempre pergunte:

o que acontece exatamente antes, exatamente no limite e exatamente depois?


🧟 CAPÍTULO 10 — Um erro correto também é PASS

Esta é deliciosa.

Mandamos:

{}

para uma operação que exige email.

Esperamos:

400

ou talvez 422, conforme o contrato adotado.

E algo como:

{
  "code": "EMAIL_REQUIRED",
  "message": "Email is required",
  "field": "email"
}

Se a aplicação rejeitar corretamente a requisição inválida...

o teste passou.

Parece contraditório somente enquanto confundimos:

API retornou erro

com:

TESTE falhou

Um teste negativo pode perfeitamente produzir:

HTTP ERROR + TEST PASS

O que seria ruim?

Enviar uma requisição inválida e receber:

500 Internal Server Error

quando o contrato previa uma rejeição controlada.

Ou pior:

400 Bad Request

mas metade da transação já foi gravada.

Constantine abre o banco de dados.

E encontra o demônio escondido lá.


🏦 CAPÍTULO 11 — COMMIT e ROLLBACK entram no exorcismo

Agora o mainframeiro começa a sorrir.

Imagine:

Criar pedido
   ↓
Debitar limite
   ↓
Diminuir estoque
   ↓
Criar pagamento

A terceira etapa falha.

O que acontece?

Se o sistema deveria tratar tudo como uma unidade lógica de trabalho, talvez esperemos:

ROLLBACK

e não:

pedido criado
limite debitado
estoque inalterado
pagamento inexistente

Esse é o tipo de criatura que aparece quando testamos apenas o status HTTP.

Recebemos:

500

e pensamos:

"Certo, falhou."

Não.

A investigação ainda não terminou.

Precisamos verificar o estado persistente.


💳 CAPÍTULO 12 — O demônio da duplicidade

Nosso BELLACARD recebe:

COMPRA = R$ 100

O cliente chama a API.

Timeout.

Não sabe se a compra aconteceu.

Tenta novamente.

Agora imagine:

REQUEST #1 → R$100
REQUEST #2 → R$100

Resultado:

R$200

Temos um problema gigantesco.

Em sistemas financeiros, retries, idempotência e mecanismos de deduplicação precisam ser considerados seriamente.

O teste não deveria perguntar somente:

A compra funcionou?

Mas:

O que acontece se a mesma operação chegar novamente?

Em determinadas APIs podemos encontrar mecanismos como:

Idempotency-Key: 8d937...

permitindo reconhecer repetições da mesma intenção.

A pergunta Constantine seria:

Quantas vezes o ritual foi executado quando o cliente jurava tê-lo invocado uma vez?


🪜 CAPÍTULO 13 — A escada dos ambientes

Agora chegamos à nova peça do quebra-cabeça:

LOCAL
  ↓
 QA
  ↓
STAGE
  ↓
PRODUCTION-LIKE

Em organizações reais podemos encontrar inúmeras variações:

DEV
INTEGRATION
QA
SIT
UAT
STAGING
PRE-PROD
PROD

Os nomes são menos importantes que o princípio.

Queremos promover software por ambientes controlados até chegarmos à produção.

No mundo mainframe isso não deveria causar nenhum choque.

Temos há décadas coisas como:

CICSD
CICST
CICSQ
CICSP

ou:

DB2D
DB2T
DB2Q
DB2P

e datasets:

BELLACOSA.DEV.CLIENTES
BELLACOSA.QA.CLIENTES
BELLACOSA.PROD.CLIENTES

DevOps não inventou a separação de ambientes.

Só mudou boa parte do vocabulário e das ferramentas.


🧙 CAPÍTULO 14 — BASE_URL: o DDNAME das APIs

Podemos ter:

BASE_URL=https://qa.api.example.com
TOKEN=***
USER_ID=42

e o teste:

await request.get(
    `${BASE_URL}/users/${USER_ID}`
);

Em Stage:

BASE_URL=https://stage.api.example.com

Em QA:

BASE_URL=https://qa.api.example.com

O teste permanece essencialmente igual.

Isso deveria soar familiar ao programador COBOL.

Em vez de amarrar recursos diretamente ao programa, usamos mecanismos externos de configuração.

No JCL:

//CLIENTE DD DSN=BELLACOSA.QA.CLIENTES,DISP=SHR

e posteriormente:

//CLIENTE DD DSN=BELLACOSA.PROD.CLIENTES,DISP=SHR

O programa não precisa ser recompilado porque mudamos de dataset.

O mesmo princípio reaparece no mundo moderno:

separe código de configuração.


☠️ CAPÍTULO 15 — .env não é um círculo mágico

Um arquivo:

.env.qa

pode conter configuração de QA.

Ótimo.

Mas cuidado:

.env ≠ Secret Vault

Colocar:

PASSWORD=123456
TOKEN=abc123

fora do source principal não torna magicamente esses valores seguros.

Segredos exigem tratamento apropriado durante armazenamento, distribuição, utilização, logging e rotação. A OWASP recomenda evitar segredos hardcoded, minimizar sua exposição e usar soluções adequadas de gestão de segredos conforme a arquitetura.

E jamais faça:

console.log(token);

e depois mande o log inteiro para:

CI REPORT
LOG SERVER
EMAIL
SLACK
ARQUIVO

Você acabou de transformar observabilidade em distribuição de credenciais.


👥 CAPÍTULO 16 — O fantasma chamado USER_ID=42

Suponha que todos os testes utilizem:

USER_ID=42

Pipeline A:

altera usuário 42

Pipeline B:

remove usuário 42

Pipeline C:

consulta usuário 42

Agora temos:

A ──┐
B ──┼── USER 42
C ──┘

Resultado?

Caos.

Um teste passa.

Outro falha.

Executamos novamente.

Passa.

Executamos amanhã.

Falha.

Nasceu o:

👻 FLAKY TEST

E então surge a frase mais perigosa do departamento de QA:

"Roda de novo."

Quando a segunda execução passa, todos vão embora.

Pouco a pouco ninguém acredita mais na suíte automatizada.

Isso destrói o valor do CI/CD.


🧬 CAPÍTULO 17 — Dê uma identidade própria para cada criatura

Uma alternativa é gerar dados únicos:

email = bellacosa+timestamp@example.test

ou utilizar:

UUID

Assim:

TEST A → USER A
TEST B → USER B
TEST C → USER C

Em vez de:

TEST A ─┐
TEST B ─┼── USER 42
TEST C ─┘

Isso aumenta isolamento e reduz colisões.

Mas abre outra porta.


🧹 CAPÍTULO 18 — Quem limpa o pentagrama depois?

Imagine 10.000 execuções criando:

USERS
CARTS
ORDERS
PAYMENTS
SESSIONS

Depois de meses:

TEST-0000001
TEST-0000002
TEST-0000003
...
TEST-9827719

QA virou um cemitério.

Por isso:

SETUP
  ↓
CREATE DATA
  ↓
EXECUTE
  ↓
ASSERT
  ↓
CLEANUP

E há um detalhe crítico:

FAIL
 ↓
CLEANUP

também.

Se a limpeza ocorrer somente quando o teste termina normalmente, justamente os testes problemáticos deixarão mais sujeira.

Constantine jamais abandonaria o pentagrama aberto no chão.

O QA também não deveria abandonar seus registros temporários.


🕵️ CAPÍTULO 19 — Nunca use o cadáver verdadeiro

A regra:

Never use real customer data.

merece atenção especial.

Copiar produção indiscriminadamente:

PROD DATABASE
      ↓
     COPY
      ↓
 QA DATABASE

pode transportar:

nomes
documentos
endereços
telefones
emails
informações financeiras
dados pessoais

para um ambiente que talvez possua controles diferentes de produção.

Dependendo da necessidade, estratégias podem envolver dados sintéticos, mascaramento, anonimização ou tokenização, considerando requisitos técnicos e regulatórios aplicáveis.

E há outro teste maravilhoso:

compare aquilo que a interface mostra com aquilo que a API realmente devolve.

A tela mostra:

Nome: João
Cidade: Itatiba

Mas o JSON devolve:

{
  "name": "João",
  "city": "Itatiba",
  "internalSalary": 12345,
  "cpf": "...",
  "internalRiskScore": 972,
  "passwordResetToken": "..."
}

A interface simplesmente ignorou os campos extras.

O atacante não ignora.

A OWASP recomenda examinar respostas brutas procurando informações sensíveis ou dados desnecessariamente expostos.


🔥 CAPÍTULO 20 — Não teste somente o Response

Chegamos à maior armadilha de todas.

O teste faz:

POST /orders

Recebe:

201 Created

e declara:

PASS

Constantine pergunta:

— Cadê o pedido?

Verificamos.

Existe.

— E o total?

Errado.

— E o estoque?

Diminuiu duas vezes.

— E o pagamento?

Foi criado três vezes.

— E o MQ?

Duas mensagens.

— E o banco?

COMMIT realizado.

O nosso glorioso:

201 CREATED

acabou de virar:

FAIL

Por isso um teste robusto pode precisar validar:

STATUS
HEADERS
BODY
SCHEMA
BUSINESS RULE
SIDE EFFECT
PERSISTENCE
SECURITY
PERFORMANCE

Estamos deixando de testar HTTP.

Estamos testando o sistema através do HTTP.

Essa diferença é gigantesca.


⏱️ CAPÍTULO 21 — Performance e o demônio da média

Imagine:

média = 200 ms

Parece excelente.

Só que:

90 usuários → 100 ms
10 usuários → 1.100 ms

A média esconde sofrimento.

Por isso aparecem medidas como:

p50
p95
p99

Se p95 = 800 ms, aproximadamente 95% das observações ficaram nesse valor ou abaixo, segundo a metodologia empregada.

Isso nos ajuda a enxergar a cauda.

Também podemos observar:

throughput
timeouts
error rate
CPU
memory
disk I/O
database locks
connection pools
queues
threads
retries

E retries merecem carinho especial.

Um servidor começa a ficar lento.

Clientes repetem chamadas.

O servidor recebe ainda mais trabalho.

Fica mais lento.

Clientes repetem ainda mais.

Temos:

SLOW
 ↓
RETRY
 ↓
MORE LOAD
 ↓
SLOWER
 ↓
MORE RETRIES
 ↓
☠️

O inferno distribuído encontrou seu próprio mecanismo de escala.


🤖 CAPÍTULO 22 — Automatizando o exorcismo

Podemos começar com algo pequeno em Playwright:

test('create user', async ({ request }) => {

  const response = await request.post('/users', {
    data: {
      name: 'Asha'
    }
  });

  expect(response.status()).toBe(201);

  const body = await response.json();

  expect(body.name).toBe('Asha');
});

Já é melhor do que testar manualmente toda vez.

Mas podemos evoluir:

status
+
headers
+
schema
+
body
+
business rules
+
authorization
+
side effects
+
cleanup

E executar automaticamente:

COMMIT
  ↓
BUILD
  ↓
UNIT TEST
  ↓
DEPLOY QA
  ↓
API TEST
  ↓
CONTRACT TEST
  ↓
AUTHORIZATION TEST
  ↓
INTEGRATION TEST
  ↓
SECURITY TEST
  ↓
REPORT
  ↓
QUALITY GATE

A OWASP também descreve a automação de testes de autorização como útil para detectar regressões durante o desenvolvimento e os releases.


🖥️ CAPÍTULO 23 — Constantine entra na LPAR

Agora traduzimos tudo para a língua ancestral.

APIMainframe — analogia conceitual
Requestentrada da transação
JSONestrutura de dados
Endpointponto de entrada
HTTP Methodoperação solicitada
HTTP Statusretorno técnico
Tokencontexto de segurança
AuthorizationRACF/controle de acesso conceitualmente
Request IDcorrelation ID
Side Effectresultado transacional
DatabaseDb2/IMS/VSAM
QueueMQ
Rollbackdesfazer LUW
Environmentregião/subsistema/configuração
BASE_URLconfiguração externa/endereço do destino
Test Datamassa de testes

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

São pontes mentais.

E elas mostram uma coisa fascinante:

muito daquilo que o mercado chama hoje de arquitetura moderna possui problemas que mainframeiros conhecem há décadas.

Estado.

Concorrência.

Segurança.

Transações.

Auditoria.

Ambientes.

Configuração.

Recuperação.

Integridade.


🕯️ CAPÍTULO 24 — O exorcismo final

Constantine está diante do monitor.

O teste apresenta:

HTTP/1.1 200 OK

Todo mundo comemora.

Ele não.

Primeira pergunta:

O usuário correto recebeu os dados?

Sim.

O schema está correto?

Sim.

A autorização foi verificada?

Sim.

Existe informação sensível extra?

Não.

O banco ficou consistente?

Sim.

A operação aconteceu uma única vez?

Sim.

As mensagens corretas foram produzidas?

Sim.

O tempo ficou dentro do objetivo definido?

Sim.

O teste utilizou dados isolados?

Sim.

O ambiente era realmente QA?

Sim.

Os segredos ficaram protegidos?

Sim.

A massa criada foi limpa?

Sim.

Agora Constantine olha novamente:

200 OK

E finalmente diz:

— Agora talvez esteja OK.


☕ EPÍLOGO — CC 0000 também pode mentir

Aqui está a lição que une o velho mainframe às APIs modernas.

Nós já aprendemos há décadas que:

CC 0000

não significa necessariamente:

NEGÓCIO CORRETO

Um batch COBOL pode terminar lindamente com:

MAXCC=0000

e ter atualizado 50.000 clientes com a tarifa errada.

Tecnicamente terminou.

Funcionalmente foi uma catástrofe.

Da mesma maneira:

HTTP 200 OK

não significa:

TEST PASSED

Nosso verdadeiro ritual é:

REQUEST VÁLIDO
       +
CONTRATO CORRETO
       +
AUTENTICAÇÃO
       +
AUTORIZAÇÃO
       +
DADOS CORRETOS
       +
REGRA DE NEGÓCIO
       +
SIDE EFFECT CORRETO
       +
ESTADO CONSISTENTE
       +
ISOLAMENTO
       +
SEGURANÇA
       +
PERFORMANCE
       +
CLEANUP
       =
       PASS

E existe ainda uma última possibilidade, aquela que faria Constantine sorrir.

O sistema está correto.

O endpoint está correto.

O banco está correto.

A autorização está correta.

O COMMIT está correto.

Mas o pipeline acusa:

FAILED

Porque dois testes resolveram utilizar simultaneamente:

USER_ID=42

Nesse momento o verdadeiro monstro não está na API.

Está na suíte de testes.

E é por isso que o bom investigador nunca pergunta apenas:

“A API falhou?”

Ele pergunta:

“O que exatamente falhou: o request, o contrato, a autenticação, a autorização, a aplicação, a regra de negócio, a persistência, o ambiente, a configuração, a massa de dados... ou o próprio teste?”

Essa é a diferença entre apertar SEND no Postman e realmente compreender API Testing.

Às 03:17, quando o dashboard fica vermelho e alguém aparece no War Room dizendo “mas estava retornando 200!”, talvez seja tarde demais para chamar John Constantine.

Mas ainda dá tempo de chamar um velho programador COBOL.

Ele provavelmente olhará para aquele 200 OK, lembrará de todos os CC 0000 que já viu mentirem durante a carreira e fará a única pergunta que realmente importa:

— Certo. Mas o que foi gravado no banco? ☕🕯️



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...