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:
- Envie a requisição enquanto a API está se comportando.
- Abra a aba Contract do editor de requisições — entre Variables e Post-Response — e aperte Derive from response.
- 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.
additionalPropertiesnã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 fieldidis 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):
- 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
contracte o JSON um campocontract, os dois compassed,failed(n),invalid_schemaounot_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 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, na 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.