Referência de configuração YAML
Esta página é escrita à mão, narrativa e organizada por caso de uso — comece por aqui. Uma
referência gerada a partir do schema também está disponível
(../articles/reference/schema.md), exaustiva e sempre em dia
com o código, útil para conferir o vocabulário completo de um objeto de uma vez. As duas convivem
de propósito, não são a mesma coisa reescrita duas vezes.
Esta página documenta, campo a campo, todo o vocabulário de um documento pipevine.dev/v1. Para
uma introdução guiada com exemplos, veja o guia; para o catálogo de
steps (o que cada type: dentro de um pipeline aceita), veja a
referência de steps, gerada a partir do código.
Documento raiz
apiVersion: pipevine.dev/v1
kind: Application
metadata: { ... }
spec: { ... }
| Campo |
Tipo |
Obrigatório |
Descrição |
apiVersion |
string |
sim |
Identifica a versão do vocabulário YAML. Sempre pipevine.dev/v1 hoje — veja Versionamento |
kind |
string |
sim |
Sempre Application |
metadata |
objeto |
sim |
Identificação da aplicação — ver seção abaixo |
spec |
objeto |
sim |
Onde o comportamento da aplicação é declarado — ver seções abaixo |
| Campo |
Tipo |
Obrigatório |
Descrição |
name |
string |
sim |
Identificador da aplicação |
version |
string |
sim |
Versão da aplicação (não confundir com apiVersion, a versão do vocabulário) |
description |
string |
não |
Descrição livre da aplicação |
spec.type
| Campo |
Tipo |
Obrigatório |
Descrição |
type |
api | consumer |
sim |
api expõe rotas HTTP (spec.routes); consumer consome mensagens de um broker (spec.consumers). Os dois compartilham exatamente o mesmo modelo de pipeline |
spec.routes (para spec.type: api)
routes:
- id: createOrder
method: POST
path: /orders/{orderId}
summary: Cria um pedido
tags: [orders]
request: { ... }
authorize: { ... }
transaction: required
cache: { ... }
pipeline: [ ... ]
response: { ... }
errors: [ ... ]
| Campo |
Tipo |
Obrigatório |
Descrição |
id |
string |
sim |
Identificador da rota dentro da aplicação |
method |
GET | POST | PUT | PATCH | DELETE | HEAD | OPTIONS |
sim |
Verbo HTTP |
path |
string |
sim |
Caminho da rota, com parâmetros entre chaves ({orderId}), disponíveis em input.route |
summary |
string |
não |
Alimenta a documentação OpenAPI gerada |
tags |
lista de string |
não |
Alimenta a documentação OpenAPI gerada |
request |
objeto |
não |
O que a rota aceita — ver seção request abaixo |
auth |
objeto ({ scheme, ref }) |
não |
Sobrescreve spec.auth.default só para esta rota |
anonymous |
boolean |
não |
Dispensa autenticação nesta rota especificamente |
authorize |
objeto |
não |
Regras de autorização — ver seção authorize abaixo |
transaction |
none | required |
não |
required abre uma transação de banco em volta de todo o pipeline da rota — necessário para mais de uma escrita atômica, ou para publish com mode: outbox |
cache |
objeto |
não |
Cache-aside da resposta inteira — ver seção cache abaixo |
pipeline |
lista de step |
não |
A sequência de steps executada para esta rota — ver referência de steps |
response |
objeto |
não |
Como montar a resposta HTTP — ver seção response abaixo |
errors |
lista de objeto |
não |
Mapeamento de código de erro → resposta HTTP — ver seção errors abaixo |
request
| Campo |
Tipo |
Obrigatório |
Descrição |
body.schema |
string (nome de uma entrada de spec.schemas) |
não |
Não é um caminho de arquivo — é o name de um schema declarado em spec.schemas; referenciar um nome não declarado falha o build. Alimenta a documentação OpenAPI gerada — a validação de corpo em runtime continua sendo responsabilidade do step validate, explicitamente no pipeline |
body.contentType |
string |
não |
Content type esperado do corpo |
headers[].name |
string |
sim |
Nome do header |
headers[].required |
boolean |
não |
Quando true, a ausência do header já responde 400 automaticamente, antes do pipeline rodar |
headers[].description |
string |
não |
Alimenta a documentação OpenAPI gerada |
query[].name |
string |
sim |
Nome do parâmetro de query |
query[].type |
string |
não |
Tipo do parâmetro (string, boolean, integer, ...) |
query[].required |
boolean |
não |
Quando true, a ausência do parâmetro já responde 400 automaticamente |
query[].default |
— |
não |
Valor usado quando o parâmetro não é informado e não é obrigatório |
authorize
| Campo |
Tipo |
Obrigatório |
Descrição |
scopes |
lista de string |
não |
Escopos exigidos do token/identidade autenticada |
roles |
lista de string |
não |
Papéis exigidos |
claims |
mapa string → string |
não |
Claims específicas exigidas, por nome e valor |
expr |
expressão JSONata |
não |
Política de autorização livre, avaliada sobre o estado do pipeline (tipicamente input.claims) |
cache (bloco da rota)
| Campo |
Tipo |
Obrigatório |
Descrição |
key |
expressão JSONata |
sim |
Chave de cache da resposta inteira |
ttl |
duração (ex.: 5m) |
não |
Tempo de vida absoluto da entrada |
tags |
lista de string |
não |
Tags para invalidação em grupo via cache.invalidate |
bypassWhen |
expressão JSONata |
não |
Quando verdadeira, ignora o cache para aquela requisição específica |
response
| Campo |
Tipo |
Obrigatório |
Descrição |
status |
integer |
não |
Status HTTP da resposta de sucesso |
headers |
mapa string → expressão |
não |
Headers da resposta, cada valor avaliado como expressão JSONata |
body |
expressão JSONata |
não |
Corpo da resposta |
schema |
string (nome de uma entrada de spec.schemas) |
não |
Não é um caminho de arquivo — é o name de um schema declarado em spec.schemas. Serve à documentação OpenAPI gerada |
errors
| Campo |
Tipo |
Obrigatório |
Descrição |
code |
string |
sim |
Código de erro produzido em algum ponto do pipeline. Além dos que você mesmo define com fail, quase todo step embutido emite um código próprio ao falhar (db_persist_failed, http_call_failed, validation_failed, ...) |
status |
integer |
na prática, sim |
Status HTTP na resposta ProblemDetails. Ver o aviso abaixo: omitir não herda o status da falha |
title |
string |
não |
Título legível na resposta ProblemDetails |
Omitir status: força 500. Quando uma entrada de errors: casa com o código da falha, o
status dela é usado sempre — e, se você não declarou status:, ele já vale 500. O status que o
próprio step produziu é descartado nesse caso. Uma entrada como
{ code: CUSTOMER_NOT_FOUND, title: "Cliente não encontrado" } combinada com um
fail ... status: 404 responde 500, não 404. Declare status: em toda entrada de errors:,
ou não declare a entrada.
spec.consumers (para spec.type: consumer)
Os steps disponíveis dentro de pipeline são exatamente os mesmos do tipo api.
consumers:
- id: onOrderPaid
source: rabbit-main
queue: orders.paid
concurrency: 4
prefetch: 20
retry: { ... }
deadLetter: { queue: orders.paid.dlq }
idempotency: { ... }
pipeline: [ ... ]
| Campo |
Tipo |
Obrigatório |
Descrição |
id |
string |
sim |
Identificador do consumidor |
source |
string |
sim |
Referência a um item de spec.brokers |
queue |
string |
não |
Fila a consumir (RabbitMQ) |
topic |
string |
não |
Tópico a consumir (Kafka) |
consumerGroup |
string |
não |
Grupo de consumidores (Kafka) |
concurrency |
integer |
não |
Número de mensagens processadas em paralelo |
prefetch |
integer |
não |
Quantidade de mensagens pré-buscadas do broker |
retry.attempts |
integer |
não |
Número de tentativas antes de considerar a mensagem uma falha definitiva |
retry.backoff.initial |
duração |
não |
Espera antes da primeira nova tentativa |
retry.backoff.max |
duração |
não |
Teto do backoff exponencial |
retry.backoff.jitter |
boolean |
não |
Adiciona variação aleatória ao backoff, para evitar tentativas sincronizadas |
retry.on |
lista de integer |
não |
Não se aplica a um consumidor — o campo existe porque a mesma estrutura de retry é compartilhada com spec.integrations, onde filtra por status HTTP. Num consumidor, toda falha é retentada; declarar on: aqui não tem efeito |
deadLetter.queue |
string |
sim (dentro de deadLetter) |
Fila para onde a mensagem vai depois de esgotar as tentativas |
idempotency.key |
expressão JSONata |
sim (dentro de idempotency) |
Identifica a mensagem de forma única — precisa ser única por consumidor, não só por entidade de negócio |
idempotency.store |
string |
não |
Referência a onde a chave de idempotência é registrada |
idempotency.ttl |
duração |
não |
Por quanto tempo a chave é lembrada |
pipeline |
lista de step |
não |
A sequência de steps executada para cada mensagem — ver referência de steps |
spec.auth
auth:
default: { scheme: jwt, ref: corp-idp }
schemes:
- { id: corp-idp, scheme: jwt, authority: "${config:Idp:Authority}", audience: orders-api }
| Campo |
Tipo |
Obrigatório |
Descrição |
default.scheme / default.ref |
string |
sim (dentro de default) |
Esquema aplicado a toda rota que não declara auth:/anonymous: true explicitamente |
schemes[].id |
string |
sim |
Identificador do esquema, referenciado por ref em auth/default/authorize |
schemes[].scheme |
string |
sim |
Qual implementação: jwt, oidc, mtls, basic, ou uma chave de terceiro |
Os campos específicos de cada esquema (authority, signingKey, caCertificatePath, users, e os
demais) estão detalhados em Autenticação e autorização,
com um exemplo completo de cada um dos quatro esquemas embutidos.
spec.dataSources e spec.entities
dataSources:
- { id: postgres-main, provider: postgres, connectionString: "${config:ConnectionStrings:Main}" }
entities:
- name: Order
table: orders
dataSource: postgres-main
key: id
properties:
- { name: id, type: uuid }
- { name: customerId, type: uuid, index: true }
- { name: total, type: decimal, precision: 18, scale: 2 }
- { name: items, type: jsonb }
- { name: createdAt, type: timestamptz }
| Campo |
Tipo |
Obrigatório |
Descrição |
dataSources[].id |
string |
sim |
Identificador da fonte de dados, referenciado por entities[].dataSource |
dataSources[].provider |
string |
sim |
Qual implementação: postgres, mysql, sqlite (os três relacionais do core) ou uma chave de terceiro |
dataSources[].connectionString |
string |
depende do provider |
String de conexão, tipicamente via ${config:...}/${env:...} |
entities[].name |
string |
sim |
Nome da entidade, referenciado pelos steps db.* |
entities[].table |
string |
sim |
Tabela/coleção de armazenamento |
entities[].dataSource |
string |
sim |
Referência a um item de dataSources |
entities[].key |
string |
sim |
Campo usado como chave primária pelos steps db.find/db.update/db.delete |
entities[].properties[].name |
string |
sim |
Nome do campo |
entities[].properties[].type |
string |
sim |
Um de: uuid, string, int/integer, long, decimal, bool/boolean, datetime, timestamptz, jsonb/json |
entities[].properties[].precision / .scale |
integer |
não |
Só para type: decimal |
entities[].properties[].index |
boolean |
não |
Cria um índice nesse campo no bootstrap de tabela |
entities[].options |
objeto livre |
depende do provider |
Configuração específica do provider de dados. O core não valida seus campos — quem valida é o provider, no build, nomeando a entidade e o campo desconhecido. É aqui que vivem partitionKey/clusteringKeys (Cassandra), partitionKey/sortKey/indexes (DynamoDB) e allowFiltering/allowScan. Ver Bancos NoSQL |
Conversão de tipos por provider relacional
Todo token de type: acima é aceito pelos três providers relacionais (postgres/mysql/sqlite),
mas nem todos são nativos nos três — onde não são, o provider converte, e a conversão pode perder
informação:
type: |
postgres |
mysql |
sqlite |
uuid |
uuid nativo |
char(36) |
TEXT |
string |
text |
text (chave primária: varchar(255) — MySQL exige comprimento para indexar) |
TEXT |
int/integer, long |
integer/bigint |
int/bigint |
INTEGER |
decimal (precision/scale) |
numeric(p,s) exato |
decimal(p,s) exato |
sem tipo decimal nativo — vira TEXT com o conversor exato do próprio EF Core Sqlite (não REAL); round-trip do valor é exato, mas ORDER BY/comparação via SQL cru contra a coluna é lexicográfico, não numérico (db.query/sort: continua correto — o EF Core Sqlite registra uma collation EF_DECIMAL para isso) |
bool/boolean |
boolean |
tinyint(1) |
INTEGER |
datetime |
timestamp |
datetime(6) |
TEXT |
timestamptz |
timestamptz — perde o offset original: todo timestamptz normaliza para UTC internamente (armazenamento, não conversão) em todos os três providers; instante e fração de segundo sobrevivem exatos, o offset não |
datetime(6) UTC — mesma perda de offset; fração de segundo preservada |
TEXT ISO-8601 — mesma perda de offset |
jsonb/json |
jsonb/json nativos |
json nativo (não distingue jsonb) |
sem tipo JSON nativo — vira TEXT |
db.sql (o escape hatch) não tem acesso ao tipo declarado da coluna — quem escreve o SQL cru é
responsável por qualquer cast/collation que o dialeto do banco exigir (ex.: @id::uuid no Postgres;
COLLATE NOCASE para comparar um uuid no SQLite, já que o driver o grava como TEXT em
maiúsculas).
spec.caches
caches:
- { id: redis-main, provider: redis, connectionString: "${config:Redis}", failOpen: true }
| Campo |
Tipo |
Obrigatório |
Descrição |
id |
string |
sim |
Identificador do cache, referenciado pelos steps cache.* e pelo bloco cache: da rota |
provider |
string |
sim |
Qual implementação: redis (referência) ou uma chave de terceiro |
connectionString |
string |
depende do provider |
String de conexão |
failOpen |
boolean |
não |
Quando true, uma falha do backend de cache é tratada como cache miss em vez de derrubar a requisição — recomendado |
Só um recurso de cache por aplicação — a rota e os steps cache.* nunca referenciam qual, apenas
declaram cache:/cache: <id>.
spec.brokers e spec.events
brokers:
- { id: rabbit-main, provider: rabbitmq, connectionString: "${config:Rabbit}" }
- { id: kafka-main, provider: kafka, bootstrapServers: "${config:Kafka}" }
events:
- name: OrderCreated
schema: Orders.OrderCreated # nome de uma entrada de spec.schemas
broker: kafka-main
topic: orders.v1
partitionKey: "payload.customerId"
description: Emitido quando um pedido é aceito
| Campo |
Tipo |
Obrigatório |
Descrição |
brokers[].id |
string |
sim |
Identificador do broker, referenciado por events[].broker e spec.consumers[].source |
brokers[].provider |
string |
sim |
Qual implementação: rabbitmq, kafka (referência) ou uma chave de terceiro |
brokers[].connectionString / .bootstrapServers |
string |
depende do provider |
Endereço do broker |
events[].name |
string |
sim |
Nome do evento, referenciado pelo step publish |
events[].schema |
string (nome de uma entrada de spec.schemas) |
não |
Não é um caminho de arquivo — é o name de um schema declarado em spec.schemas, alimentando o AsyncAPI gerado. Diferente de request.body.schema numa rota, este não é validado no build: um nome inexistente não falha nada, só produz um AsyncAPI sem o schema |
events[].broker |
string |
sim |
Referência a um item de brokers |
events[].topic |
string |
sim |
Tópico/routing key de destino |
events[].partitionKey |
expressão JSONata |
não |
Chave de particionamento, avaliada sobre o payload publicado |
events[].description |
string |
não |
Alimenta o AsyncAPI gerado |
spec.storages
Os recursos de blob storage que os steps storage.* referenciam por id. Ver
Blob storage para o uso ponta a ponta.
storages:
- id: docs
provider: s3
config:
endpoint: "${config:Storage:Endpoint}"
region: us-east-1
bucket: docs
accessKeyId: "${secret:env:STORAGE_ACCESS_KEY}"
secretAccessKey: "${secret:env:STORAGE_SECRET_KEY}"
forcePathStyle: true
| Campo |
Tipo |
Obrigatório |
Descrição |
id |
string |
sim |
Identificador do storage, referenciado pelo campo storage: dos steps storage.* |
provider |
string |
sim |
Qual implementação: s3 (que cobre AWS S3, MinIO e RustFS — mesmo protocolo) ou uma chave de terceiro |
config |
objeto livre |
depende do provider |
Configuração do provider. O core não valida seus campos; quem valida é o próprio provider, no build |
Campos de config aceitos pelo provider s3:
| Campo |
Obrigatório |
Descrição |
bucket |
sim |
Bucket de destino |
endpoint |
não |
Endereço do serviço. Obrigatório para MinIO/RustFS; omitido, usa o endpoint padrão da AWS para a region |
region |
não |
Região AWS |
accessKeyId / secretAccessKey |
não |
Credenciais. Precisam ser ${secret:...} — um literal é recusado no startup. Omitidas, o SDK usa a cadeia de credenciais padrão da AWS |
forcePathStyle |
não |
true para endereçamento por caminho, tipicamente exigido por MinIO e RustFS |
spec.integrations
integrations:
- id: pricing
kind: http
baseUrl: "${config:Pricing:Url}"
auth: { scheme: oauth2-client-credentials, ref: corp-idp }
resilience:
timeout: { perAttempt: 2s, total: 8s }
retry: { attempts: 3, backoff: { initial: 200ms, jitter: true }, on: [502, 503, 504] }
circuitBreaker: { failureRatio: 0.5, samplingDuration: 30s, minimumThroughput: 20, breakDuration: 15s }
fallback: { expr: "{ 'price': 0, 'degraded': true }" }
rateLimiter: { permitLimit: 50, window: 1s, queueLimit: 10 }
| Campo |
Tipo |
Obrigatório |
Descrição |
id |
string |
sim |
Identificador da integração, referenciado pelos steps http.call/grpc.call |
kind |
http | grpc |
sim |
Protocolo da integração |
baseUrl |
string |
sim |
URL base do sistema externo |
auth.scheme / .ref |
string |
não |
Esquema de autenticação de saída — reusa os mesmos esquemas de spec.auth, mais oauth2-client-credentials |
resilience.timeout.perAttempt / .total |
duração |
não |
Tempo máximo de uma tentativa, e da operação inteira (incluindo retries) |
resilience.retry.attempts |
integer |
não |
Número de tentativas |
resilience.retry.backoff.initial / .max / .jitter |
duração / duração / boolean |
não |
Backoff entre tentativas |
resilience.retry.on |
lista de integer |
não |
Status HTTP que disparam retry |
resilience.circuitBreaker.failureRatio |
number |
não |
Proporção de falhas que abre o circuito |
resilience.circuitBreaker.samplingDuration |
duração |
não |
Janela de amostragem para o cálculo da proporção |
resilience.circuitBreaker.minimumThroughput |
integer |
não |
Mínimo de chamadas na janela para o cálculo ser considerado significativo |
resilience.circuitBreaker.breakDuration |
duração |
não |
Por quanto tempo o circuito fica aberto |
resilience.fallback.expr |
expressão JSONata |
não |
Valor substituto quando a chamada falha mesmo depois de retry/circuit breaker |
resilience.fallback.pipeline |
lista de step |
não |
Alternativa a expr: um sub-pipeline inteiro executado como fallback |
resilience.rateLimiter.permitLimit |
integer |
não |
Limite de chamadas concorrentes/por janela |
resilience.rateLimiter.window |
duração |
não |
Janela de tempo do limite |
resilience.rateLimiter.queueLimit |
integer |
não |
Fila opcional para chamadas que excedem o limite instantâneo |
Um status 5xx (ou uma falha de rede) que sobrevive a todo o pipeline de resiliência executa
fallback, se declarado. Um status 4xx é sempre erro de negócio — nunca é repetido e nunca aciona
fallback. Ver Integrações outbound.
spec.schemas
schemas:
- name: OrderItem
properties:
- { name: sku, type: string, required: true }
- { name: quantity, type: int, required: true }
- name: OrderCreatePayload
properties:
- { name: customerId, type: uuid, required: true }
- { name: items, type: "OrderItem[]", required: true } # lista: sufixo [], não "array"
| Campo |
Tipo |
Obrigatório |
Descrição |
name |
string |
sim |
Nome do schema. É por ele que request.body.schema/response.schema referenciam, e é dele que sai o nome do record C# gerado |
properties[].name |
string |
sim |
Nome do campo |
properties[].type |
string |
sim |
Um de: string, int/int32, long/int64, double, decimal, bool/boolean, uuid, datetime/date-time; o name de outro schema; ou qualquer um deles com o sufixo [] para lista |
properties[].required |
boolean |
não |
Se o campo é obrigatório |
array não é um tipo válido — uma lista se escreve com o sufixo [] (string[],
OrderItem[]). Um token desconhecido não quebra o build: o campo vira JsonNode? sem tipo e o
gerador emite o diagnóstico PV3020, então repare nesse aviso em vez de assumir que passou.
Steps do pipeline
Todo step, em qualquer pipeline (de uma rota ou de um consumidor), aceita três campos universais:
| Campo |
Tipo |
Obrigatório |
Descrição |
type |
string |
sim |
A chave que resolve qual implementação executa |
id |
string |
não |
Publica o resultado do step em steps.<id>.result |
when |
expressão JSONata |
não |
O step só executa se a expressão for verdadeira. Mais barato que branch para pular um único step |
Os campos específicos de cada type: — validate, map, db.persist, cache.get, publish,
http.call, e todos os demais — estão documentados na
referência de steps, gerada a partir do código, e com exemplos no
guia. Os seis steps de controle de fluxo (branch,
switch, foreach, parallel, try, group) são sintaxe estrutural do próprio motor de pipeline,
cobertos em Controle de fluxo.