# Contratos

> Derive um JSON Schema de uma resposta que já funciona e todas as respostas seguintes são medidas contra essa forma — no painel de resposta, no runner de coleções e por MCP.

## Capture, não escreva

Ninguém escreve um JSON Schema à mão, e é por isso que contract testing quase nunca começa. O Mariner inverte o gesto:

1. Envie a requisição enquanto a API está se comportando.
2. Abra a aba **Contract** do editor de requisições — entre Variables e Post-Response — e aperte **Derive from response**.
3. Esse é o contrato. Todas as respostas dali em diante são medidas contra ele.

A aba leva um `•` sempre que a requisição promete uma forma, então você sabe antes de gastar um envio. Ela abre em **Forma**: uma linha por campo com o nome, um chip de tipo, uma marca `OBR` quando o schema exige, e o resto do que ele exigir — `format: date`, os valores de um enum, uma faixa. Vinte linhas de chaves viram oito linhas que se leem em dois segundos. **JSON** fica a um segmento de distância com o documento cru, e avisa assim que o que você digita deixa de ser JSON válido.

**Re-derive** substitui o contrato quando a API muda de forma legítima; **Clear** tira. Sem assinatura, o cabeçalho mostra um chip *Somente leitura*: o schema continua na tela para você ler, e editá-lo espera até você assinar.

O schema é um documento JSON Schema (draft 2020-12), com o título da requisição, e continua editável embaixo — cole um traduzido da sua definição de Zod, Pydantic ou OpenAPI e funciona igual.

A coleção de boas-vindas já traz um montado: **Contract → GET · Uma resposta sob contrato**. Envie e o veredito aparece; troque `/json` por `/uuid` na URL e veja quebrar.

## O que «derivado» quer dizer

Derivar lê a resposta que você tem, não a API que você gostaria de ter:

- **Só é exigido o que estava lá de verdade.** Em um array, uma chave presente em todos os elementos amostrados é obrigatória; uma que aparece em alguns é descrita, mas fica opcional.
- **Campos a mais nunca quebram.** `additionalProperties` não é emitido, então uma API que adiciona um campo continua passando — o contrato pega o que *sumiu* ou *mudou de tipo*, que é o que de fato quebra um cliente.
- **Um campo que às vezes é nulo** sai como `["string", "null"]` em vez de sair como mentira.
- **Um campo cujas amostras discordaram** sai como schema vazio: ali vale qualquer coisa. Chutar rejeitaria payloads que a API realmente manda.
- Os arrays são amostrados até 200 elementos e o aninhamento até 8 níveis.

## O veredito, onde você já está olhando

- Um chip **CONTRACT** fica ao lado do status: verde quando a resposta cumpre, âmbar com uma contagem quando há campos desviados, vermelho quando o próprio schema não é JSON válido. Clique para pular para a aba.
- A aba **Contract** do painel de resposta leva um badge âmbar com o número de violações — aceso mesmo quando você está em outra aba, porque o trabalho dele é avisar justamente da aba que você não está olhando.
- Essa aba é uma tabela, não uma lista de reclamações: cada campo que o contrato descreve com **o valor que realmente chegou** ao lado, e os desviados no topo com o motivo na própria linha. **Somente diferenças** esconde a maioria que cumpre, que é o que torna legível um contrato de quarenta campos. Clique com o botão direito numa linha para copiar o caminho.
- Cada violação é listada com seu caminho (`$.slideshow.author`) e o que houve: *Expected string, got integer*, *Required field `id` is missing*, e assim por diante. A lista para em 100.
- Sem contrato, ou com uma resposta que não é JSON? Nada é mostrado. Um chip permanente de «sem contrato» sobre os 90 % das requisições que nunca vão ter um é exatamente o que ensina a parar de ler a faixa.

**Um contrato quebrado nunca faz a requisição falhar.** O servidor respondeu; o status é o que é. A validação é informativa e diz isso: aponta qual campo se mexeu e deixa o veredito do envio com o HTTP.

## O que o validador cobre

Estrutura (`type`, `properties`, `required`, `items`, `additionalProperties`), valores (`enum`, `const`, `minimum` / `maximum`, `minLength` / `maxLength`, `pattern`, `minItems` / `maxItems`, `uniqueItems`, `multipleOf`) e composição (`anyOf`, `allOf`, `oneOf`, `not`, mais `$ref` local dentro de `$defs`).

Sem implementar, de propósito: `$dynamicRef`, `unevaluatedProperties` e a resolução de `$ref` remotos — aparecem nas suítes de conformidade, não em um schema derivado do seu próprio endpoint. `format` é tratado como a anotação que a especificação diz que é: um `"date-time"` que não parseia não é falha, porque metade das APIs do mundo quebraria o próprio contrato só por isso.

## No runner de coleções

Execute uma coleção e cada requisição com contrato é conferida no caminho ([Runner](/pt-br/docs/runner)):

- O resumo acrescenta **Off contract** e **No contract** ao lado de Passed / Failed, mas só quando pelo menos uma requisição da corrida tem contrato. Zero desvios sobre nove requisições que ninguém verifica não é boa notícia, então os dois números andam sempre juntos.
- Cada linha ganha sua célula de contrato: selo verde, contagem âmbar, marca vermelha para um schema inservível, ou `—` quando não há o que conferir.
- O relatório exportado também leva. O CSV tem uma coluna `contract` e o JSON um campo `contract`, os dois com `passed`, `failed(n)`, `invalid_schema` ou `not_json` — as mesmas palavras que um agente recebe por MCP, para que um CI e um agente falem da mesma corrida sem traduzir.

## A partir de um agente

O [servidor MCP](/pt-br/docs/mcp) expõe o mesmo veredito, calculado pelo mesmo código:

| Ferramenta | Propósito |
|---|---|
| `get_contract` | Ler o documento de schema que uma requisição promete |
| `set_contract` | Guardar um schema que você construiu, ou passar `derive_from_response: true` para enviar uma vez e derivá-lo. Devolve o schema anterior |
| `check_contract` | Enviar e conferir. `variants: "all"` testa cada variante de body salva por vez e deixa ativa a que estava |
| `check_collection_contracts` | «Essa API mudou?» para uma coleção inteira; as requisições sem contrato são informadas como não verificadas, nunca puladas em silêncio |

`send_request` e `run_collection` também incluem o veredito, então um agente que estava em outra coisa fica sabendo do mesmo jeito que a forma se mexeu.

## Onde o schema vive

O contrato pertence à requisição, não a uma resposta: é parte da definição dela, então viaja junto na [exportação e importação](/pt-br/docs/file-format), na [sincronização com o iCloud](/pt-br/docs/system#sincronização-com-o-icloud), e é o que o `get_contract` lê por MCP. Passe um pacote `.mariner` para um colega e os contratos vão junto. Fica guardado como documento cru — um schema que você colou do seu próprio repositório sai byte a byte igual, sem reformatação.

Uma requisição sem contrato não escreve chave nenhuma, então o pacote de quem nunca mexeu no recurso mantém exatamente a forma que tinha.

<aside class="callout" data-label="O MÊS GRÁTIS">
Os contratos fazem parte de todos os planos, e do <a href="/pt-br/docs/free-and-pro">mês grátis</a>. A coleção de boas-vindas já vem com um derivado, para que o veredito seja algo que você vê funcionando desde o primeiro dia.
</aside>

---
Source: https://marinerhttp.dev/pt-br/docs/contracts · Mariner docs
