Skip to content
Voltar ao blog
Tutoriais

Problema Norway do YAML e Diferenças JSON-YAML para Devs

Por que o YAML lê «no» como false. Falhas reais no K8s por aspas em strings. Escolhas JSON vs YAML, regras de indentação e conversões de manifestos K8s explicadas.

14 min de leitura

O Problema Norway do YAML e as Diferenças entre JSON ↔ YAML que Engenheiros Devem Conhecer

Foi um deployment Helm de rotina. A equipe havia passado dois dias ajustando um arquivo values.yaml para um rollout multi-região. O chart criava um ConfigMap do Kubernetes com metadados de localidade — incluindo o código de país para o datacenter norueguês. Alguém digitou country: NO e fez o commit. O pipeline de CI ficou verde. O deployment foi para produção.

Então vieram os alertas.

O ConfigMap continha country: false em vez de country: "NO". Todo serviço downstream que lia o campo country recebia um booleano em vez de uma string. A comparação de strings quebrou. A lógica de roteamento caiu para um padrão. O tráfego que deveria ter ficado na Noruega acabou sendo processado pelo endpoint regional errado.

A causa raiz era uma única string sem aspas em um arquivo YAML. YAML 1.1 — a versão que virtualmente todas as ferramentas do Kubernetes usam — trata NO como o booleano false. Ele trata YES, ON, OFF, Y, N, no, yes, on, off, y, n e uma dúzia de outras variantes da mesma forma. Sem aviso. Sem erro. Silenciosamente errado.

JSON não tem esse problema. {"country": "NO"} é sempre uma string. A coerção de tipo implícita do YAML é ao mesmo tempo sua maior conveniência e sua mais perigosa armadilha.

Este guia cobre o quadro completo: por que o problema Norway existe, o que mudou no YAML 1.2 (e por que a maioria das ferramentas o ignora), como escrever estratégias corretas de aspas, as regras de indentação que pegam os iniciantes de surpresa, armadilhas de precisão de números e quatro cenários reais de conversão, de manifestos do Kubernetes a planos do Terraform. Quando precisar converter com segurança um valor JSON para YAML sem essa armadilha, nosso conversor JSON para YAML coloca aspas automaticamente em strings propensas ao problema Norway.

JSON vs YAML — Quando Usar Cada Um

Antes de mergulhar no problema Norway, é útil entender para o que cada formato é realmente otimizado. Eles não são intercambiáveis — cada um tem um centro de design que o torna a melhor escolha em contextos específicos.

DimensãoJSONYAML
SintaxeEstrita — chaves, aspas, vírgulas obrigatóriasFlexível — baseada em indentação, pontuação mínima
Sistema de tiposExplícito: string, número, booleano, null, array, objetoImplícito — YAML 1.1 infere tipos a partir da forma do valor
Legibilidade humanaAmigável para desenvolvedores, verificável por máquinaAmigável para humanos, fácil de editar manualmente
Requisito de aspasStrings sempre entre aspasA maioria dos escalares pode ficar sem aspas (a origem do Norway)
ComentáriosNão suportadoSuportado com #
Uso principalAPIs, troca de dados, sistemas de config modernosKubernetes, Docker Compose, Ansible, pipelines de CI
Análises surpreendentesNenhuma — análise estritaSim — Norway, octal, timestamps
Aplicação de schemaEcossistema JSON SchemaYAML Schema (menos ferramentas)

JSON vence quando seus dados cruzam fronteiras de sistemas — APIs REST, filas de mensagens, serialização de banco de dados. Máquinas os analisam, máquinas os geram, e a sintaxe estrita torna a validação direta. Use um Formatador JSON para validar a estrutura antes de enviar.

YAML vence quando humanos são os principais autores. Manifestos do Kubernetes, workflows do GitHub Actions, charts Helm, playbooks do Ansible — esses são arquivos que desenvolvedores leem e editam dezenas de vezes. A pontuação reduzida e o suporte a comentários os tornam genuinamente mais fáceis de manter do que seus equivalentes JSON.

O problema surge na fronteira: quando uma ferramenta gera JSON (como kubectl get deploy -o json ou terraform show -json) e um humano precisa versionar ou editar o resultado como YAML. Essa conversão é onde o problema Norway vive. Nosso conversor YAML para JSON trata a direção inversa quando você precisa voltar.

O Problema Norway — Mergulho Profundo

O problema Norway não é um bug. É uma característica da especificação YAML 1.1 se comportando exatamente como foi projetada. Entender por que foi projetada dessa forma — e por que tantos sistemas ainda implementam a versão 1.1 — é a chave para evitá-lo.

Por que «no», «yes», «on», «off», «y», «n» São Mal Interpretados

A especificação YAML 1.1 definiu um tipo booleano amplo que pretendia ser amigável para humanos. Ela reconhecia todos os seguintes como true ou false:

Verdadeiro: y, Y, yes, Yes, YES, true, True, TRUE, on, On, ON

Falso: n, N, no, No, NO, false, False, FALSE, off, Off, OFF

A intenção era boa: arquivos de configuração frequentemente usam yes/no em vez de true/false em inglês, e o YAML queria suportar a forma natural como as pessoas escrevem configurações. O problema é que yes, no, on, off, y e n também são valores de string perfeitamente legítimos que significam algo completamente diferente na maioria das aplicações.

Aqui está a incompatibilidade em YAML concreto:

# YAML 1.1 (o que a maioria dos parsers implementa)
country: NO        # interpreta como: country: false   ← PERIGO
enabled: yes       # interpreta como: enabled: true
restart: off       # interpreta como: restart: false
language: y        # interpreta como: language: true
shell: n           # interpreta como: shell: false

# Correto — aspas explícitas substituem a inferência de tipo
country: "NO"      # interpreta como: country: "NO"    ← seguro
enabled: "yes"     # interpreta como: enabled: "yes"
restart: "off"     # interpreta como: restart: "off"
language: "y"      # interpreta como: language: "y"
shell: "n"         # interpreta como: shell: "n"

E a comparação com JSON:

{"country": "NO"}

Em JSON, NO dentro de aspas é sempre e incondicionalmente uma string. Não há inferência de tipo implícita. A rigidez que faz o JSON parecer verboso também é o que o torna seguro.

Além da coerção booleana, o YAML 1.1 também converte implicitamente:

  • 123e4 → o número 1230000 (notação científica)
  • 0x1A → o número 26 (hexadecimal)
  • 0755 → o número 493 (octal — este quebra strings de permissão de arquivo Unix)
  • 2024-05-04 → um objeto de data em muitos parsers (não apenas uma string)
  • 1_000_000 → o número 1000000 (separador de sublinhado)

O problema Norway é realmente apenas o membro mais famoso de toda uma família de coerções de tipo implícitas do YAML.

YAML 1.1 vs 1.2 — O que Mudou

O YAML 1.2 foi publicado em 2009 — quatro anos depois do YAML 1.1. Seu objetivo principal era trazer o YAML para alinhamento estrito com o JSON (já que o JSON é realmente um subconjunto válido do YAML 1.2) e reduzir as conversões de tipo implícitas surpreendentes.

No YAML 1.2:

  • Booleano é restrito a exatamente true e false (sensível a maiúsculas). É isso. yes, no, on, off são strings simples.
  • Literais octais exigem o prefixo 0o (0o755) — a forma antiga 0755 é uma string.
  • Timestamps não são analisados implicitamente — 2024-05-04 permanece como uma string, a menos que você a marque explicitamente.
  • A especificação em si é um superconjunto do JSON, o que significa que todo documento JSON válido é YAML 1.2 válido.

No papel, o YAML 1.2 resolve o problema Norway completamente. Na prática, o ecossistema mal se moveu.

BibliotecaEspecificação padrãoRisco Norway
PyYAML (Python)YAML 1.1Sim — yaml.safe_load ainda interpreta NO como False
ruamel.yaml (Python)YAML 1.2 (opcional)Configurável — mais seguro por padrão
js-yaml (Node.js)YAML 1.1Sim em versões mais antigas; versões mais recentes têm opção FAILSAFE_SCHEMA
eemeli/yaml (Node.js)YAML 1.2Não — 1.2 por padrão, ou selecionável explicitamente
gopkg.in/yaml.v2 (Go)YAML 1.1Sim
gopkg.in/yaml.v3 (Go)YAML 1.2Significativamente mais seguro
Kubernetes / HelmYAML 1.1 (via Go yaml.v2)Sim — histórico, muito difícil de migrar
AnsibleYAML 1.1 (via PyYAML)Sim

A razão pela qual a migração é lenta é a compatibilidade retroativa. Sistemas que dependem de yes/no sendo analisados como booleanos por uma década não podem silenciosamente mudar esse comportamento sem quebrar as configurações existentes. Kubernetes em particular tem uma enorme base instalada onde mudar a semântica de análise YAML seria uma mudança destrutiva para todo o cluster.

A conclusão prática: assuma semântica YAML 1.1 em qualquer ferramenta que você não configurou explicitamente de outra forma. Sempre coloque aspas em strings que poderiam ser mal interpretadas como booleanos, timestamps ou números.

Como Sistemas em Produção São Afetados

O código de país da Noruega é o exemplo mais citado porque é contraintuitivo — NO parece uma abreviação óbvia, não um booleano. Mas o padrão se repete em muitos cenários do mundo real:

Códigos de aeroporto IATA. O aeroporto norueguês Harstad/Narvik tem o código EVE. Seguro. Oslo Gardermoen é OSL. Também seguro. Mas qualquer aplicação usando YAML para armazenar códigos de aeroporto regionais está a um código de rota no de distância de um booleano falso em produção.

Nomes de variáveis de ambiente. ON é um valor de variável de ambiente perfeitamente válido, significando «habilitado» em alguns sistemas legados. OFF é sua contraparte. Migrar configurações de scripts shell para YAML sem colocar aspas nesses valores introduz coerção de tipo silenciosa.

Campos de usuário de e-mail. Um usuário cujo primeiro nome ou nome de usuário seja literalmente n, y ou qualquer uma das palavras de gatilho será serializado incorretamente se a aplicação despejar YAML sem aspas adequadas. Isso é particularmente insidioso porque falha apenas para um subconjunto de usuários.

Políticas de reinicialização do Docker Compose. O valor "no" do campo restart_policy significa «não reiniciar». Se perder suas aspas em um round-trip YAML, o valor se torna false, e o Docker Compose pode interpretá-lo como «nenhuma política de reinicialização especificada» ou lançar um erro de validação — de qualquer forma, o comportamento de reinicialização do container está errado.

Campo shell: do GitHub Actions. Os valores de shell válidos são bash, pwsh, python, sh, cmd, powershell. Nenhum deles é palavra Norway. Mas alguém que digita shell: yes ou shell: on como placeholder durante a edição de rascunho pode se surpreender quando o YAML o transforma em um booleano antes mesmo de o validador o ver.

A correção em todos os casos é a mesma: coloque aspas em strings que são semanticamente strings, independentemente de um humano as reconhecer como palavras-chave. Nosso conversor JSON para YAML aplica isso automaticamente — qualquer valor na lista de palavras Norway recebe aspas na saída.

Estratégia de Aspas em Strings

Uma vez que você entende por que as palavras Norway geram incompatibilidades, a solução é escolher a estratégia de aspas certa para seu caso de uso. O YAML suporta três modos, cada um com diferentes trocas.

Auto vs Duplas vs Simples

Aspas automáticas (recomendado para a maioria das conversões) deixa a biblioteca decidir quando as aspas são necessárias. Valores que seriam mal interpretados sem aspas — palavras Norway, números, timestamps, strings que parecem sintaxe YAML — recebem aspas automaticamente. Todo o resto fica como um escalar simples. Isso produz a saída mais legível enquanto permanece seguro.

# Saída no modo Auto
name: Alice          # simples — sem ambiguidade
country: "NO"        # entre aspas — palavra Norway
age: 30              # simples — número sem ambiguidade
created: "2024-05-04" # entre aspas — seria analisado como data
port: "8080"         # depende da biblioteca — algumas colocam aspas em strings parecidas com números

Strings com aspas duplas envolvem todos os valores de string em aspas duplas. Isso é explícito e auditável — qualquer leitor pode ver que todos esses valores são strings sem raciocinar sobre a especificação. A troca é a verbosidade e a legibilidade humana reduzida, especialmente para configurações profundamente aninhadas.

# Modo de aspas duplas
name: "Alice"
country: "NO"
replicas: "3"         # até números se tornam strings — pode causar erros de schema

Cuidado: se o seu schema alvo espera um número e você o serializa como uma string entre aspas, o parser YAML o tipará corretamente como uma string, mas o Kubernetes ou outro consumidor estrito pode rejeitar o campo como sendo do tipo errado.

Strings com aspas simples são uma característica exclusiva do YAML — JSON não tem sintaxe de aspas simples. Aspas simples são literais: sem sequências de escape dentro delas. O único caso especial é que uma aspa simples dentro de uma string com aspas simples deve ser duplicada (''). Aspas simples são ideais para strings que contêm barras invertidas ou caracteres especiais que precisariam de escape em aspas duplas.

# Modo de aspas simples
pattern: 'C:\Users\alice\Documents'  # sem escape necessário
regex: '\d+\.\d+'                    # barras invertidas literais

Para conversões JSON para YAML que pretendem fazer round-trip de volta para JSON, prefira o modo Auto ou Duplas. Strings com aspas simples introduzem uma sintaxe específica do YAML que requer um parser ciente do YAML no caminho de volta.

Escalares de Bloco (| e >)

A sintaxe de escalar de bloco do YAML é genuinamente útil para strings multilinha — algo que o JSON trata de forma desajeitada com sequências de escape \n.

Escalar de bloco literal | preserva quebras de linha exatamente:

# Bloco literal — quebras de linha mantidas
script: |
  #!/bin/bash
  set -euo pipefail
  echo "Starting deployment"
  kubectl apply -f manifest.yaml

# Representação JSON equivalente (ilegível)
# {"script": "#!/bin/bash\nset -euo pipefail\necho \"Starting deployment\"\nkubectl apply -f manifest.yaml\n"}

Escalar de bloco dobrado > junta linhas com espaços, transformando cada quebra de linha em um espaço (exceto linhas em branco, que se tornam quebras de linha):

# Bloco dobrado — quebras de linha se tornam espaços
description: >
  Este serviço trata autenticação
  para toda a plataforma. Suporta
  OAuth2, SAML e autenticação por chave de API.

# Resultado: "Este serviço trata autenticação para toda a plataforma. Suporta OAuth2, SAML e autenticação por chave de API.\n"

Escalares de bloco brilham para incorporar certificados TLS, scripts shell multilinha ou consultas SQL em configurações YAML — cenários onde o equivalente JSON seria uma string longa, com escape e em uma única linha que nenhum humano consegue ler.

Ao converter de JSON para YAML, a maioria dos conversores (incluindo o nosso) usa o modo Auto e representa strings multilinha com escalares de bloco apenas quando detectam quebras de linha incorporadas. Strings de uma única linha recebem escalares de fluxo (entre aspas ou simples). Use nosso conversor JSON para YAML para ver a saída antes de committá-la em um manifesto.

Indentação — 2 vs 4 Espaços, Tabs Proibidos

As regras de indentação do YAML são mais estritas do que parecem. A especificação tem uma regra absoluta e uma convenção que varia por ecossistema.

A regra absoluta: tabs são proibidos. Cada nível de indentação deve usar espaços. Um caractere tab em um arquivo YAML é um erro de análise na maioria dos parsers:

# ERRADO — tabs causam erros de análise
apiVersion: apps/v1
kind: Deployment
metadata:
	name: my-app     # ← caractere tab aqui → ParseError

# CORRETO — apenas espaços
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app      # ← dois espaços

A mensagem de erro que você verá varia por biblioteca. No PyYAML do Python:

yaml.scanner.ScannerError: while scanning for the next token
found character '\t' that cannot start any token

No yaml.v3 do Go:

yaml: line 4: found character that cannot start any token

Configure seu editor para expandir tabs em espaços para arquivos YAML. No VS Code, adicione às configurações do workspace: "[yaml]": { "editor.insertSpaces": true, "editor.tabSize": 2 }.

A convenção: 2 vs 4 espaços. Ambos são válidos. As convenções do ecossistema diferem:

EcossistemaConvençãoRazão
Manifestos Kubernetes2 espaçosDocumentação e exemplos oficiais usam 2
Charts Helm2 espaçosSegue a convenção do K8s
Docker Compose2 espaçosExemplos da especificação compose oficial
GitHub Actions2 espaçosExemplos de workflow oficiais
Playbooks Ansible2 espaçosDocumentação oficial
Configs tradicionais4 espaçosCorresponde ao padrão de embelezamento do JSON

Para qualquer arquivo que será consumido pelo Kubernetes ou Docker Compose, use 2 espaços. Para arquivos de configuração autônomos que serão lidos apenas por humanos e ferramentas personalizadas, qualquer um funciona — apenas seja consistente dentro de um arquivo. Nosso conversor JSON para YAML usa 2 espaços de indentação por padrão e permite que você mude para 4 para projetos que preferem isso.

Mais uma regra: elementos filhos devem ser indentados mais que seus pais, mas o número de espaços adicionais pode ser qualquer inteiro positivo (1, 2, 3, 4…) — desde que seja consistente dentro de um bloco. Na prática, sempre use 2 ou 4 para legibilidade.

Tratamento de Números entre JSON ↔ YAML

Ambos os formatos suportam números, mas os casos extremos diferem o suficiente para causar bugs em produção.

Perda de Precisão para Números Grandes

O tipo Number do JavaScript é um float IEEE 754 de 64 bits. Ele pode representar inteiros exatamente até 2^53 − 1 = 9.007.199.254.740.991. Além disso, a precisão inteira é perdida:

// Perda de precisão do JavaScript — não é um problema do YAML, mas afeta a análise JSON
JSON.parse('{"v": 9007199254740993}').v
// → 9007199254740992   (o 3 se tornou 2 — um bit perdido)

// Seguro — dentro do intervalo 2^53
JSON.parse('{"v": 9007199254740991}').v
// → 9007199254740991   (exato)

Isso importa para a conversão JSON para YAML em ambientes JavaScript porque a precisão já é perdida antes que a serialização YAML comece. O metadata.resourceVersion do Kubernetes é um campo de string especificamente porque as versões de recurso podem exceder o intervalo seguro de inteiros. Outros campos que parecem números pequenos — observedGeneration, componentes de uid — são mais seguros, mas qualquer campo int64 em uma resposta K8s é potencialmente afetado.

Soluções:

  • Use Python ou Go para pipelines de conversão envolvendo números grandes — ambos lidam com inteiros arbitrários nativamente.
  • No Node.js, use um parser JSON que suporte BigInt: JSON.parse(text, (_, v) => typeof v === 'number' && !Number.isSafeInteger(v) ? BigInt(v) : v).
  • Para campos que devem fazer round-trip sem perda, serialize-os como strings na fonte.
  • Ao revisar YAML convertido, procure por campos como resourceVersion, generation e valores derivados de timestamp.

Peculiaridades de Octal e Hex

O YAML 1.1 trata certas strings parecidas com números como inteiros não decimais:

# Surpresas de análise do YAML 1.1
permissions: 0755   # interpreta como octal 493, não decimal 755
value: 0x1A         # interpreta como hex 26, não string "0x1A"

# Comportamento do YAML 1.2
permissions: 0755   # fica como inteiro 755 (decimal) — octal exige prefixo 0o
permissions: 0o755  # interpreta como octal 493 em ambos 1.1 e 1.2

# Seguro para ambas as especificações — coloque aspas em qualquer valor com zero à esquerda
permissions: "0755"  # sempre a string "0755"

A armadilha octal é particularmente perigosa para permissões de arquivo Unix, componentes de endereço IP com zeros à esquerda (alguns dispositivos de rede) e qualquer código numérico que use zeros à esquerda para preenchimento (CEPs, códigos de produto). Sempre coloque aspas nesses valores ao escrever YAML à mão, ou garanta que seu conversor os coloque entre aspas — nosso conversor JSON para YAML detecta strings numéricas do JSON e preserva seu tipo de string.

Conversões do Mundo Real

O problema Norway e as estratégias de aspas se tornam concretos quando você os aplica a cenários reais de conversão.

Manifesto Kubernetes a partir de JSON

O workflow canônico: kubectl get deploy my-app -o json fornece o objeto ao vivo como JSON. Você quer limpá-lo (remover status, creationTimestamp, campos gerenciados) e commitá-lo no git como um manifesto YAML.

JSON fonte (abreviado):

{
  "apiVersion": "apps/v1",
  "kind": "Deployment",
  "metadata": {
    "name": "my-app",
    "namespace": "production",
    "labels": {
      "app": "my-app",
      "region": "NO"
    }
  },
  "spec": {
    "replicas": 3,
    "selector": {
      "matchLabels": { "app": "my-app" }
    },
    "template": {
      "spec": {
        "containers": [{
          "name": "app",
          "image": "registry.example.com/my-app:v1.2.3",
          "env": [
            { "name": "REGION", "value": "NO" },
            { "name": "ENABLE_FEATURE", "value": "yes" }
          ]
        }]
      }
    }
  }
}

Saída YAML esperada (com proteção Norway):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
  labels:
    app: my-app
    region: "NO"          # entre aspas — palavra Norway
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    spec:
      containers:
        - name: app
          image: registry.example.com/my-app:v1.2.3
          env:
            - name: REGION
              value: "NO"           # entre aspas — palavra Norway
            - name: ENABLE_FEATURE
              value: "yes"          # entre aspas — palavra Norway

Observe que replicas: 3 é deixado sem aspas — é um inteiro legítimo que o Kubernetes espera como número. As palavras Norway em labels e valores de env estão entre aspas. Um conversor ingênuo que não trata os booleanos YAML 1.1 produziria silenciosamente region: false e value: false.

Após converter, valide com: kubectl apply --dry-run=client -f manifest.yaml. Isso detecta erros de schema sem tocar no cluster.

Experimente a conversão em nosso conversor JSON para YAML — cole o JSON acima e veja a saída segura ao problema Norway instantaneamente. Use nosso conversor YAML para JSON para verificar o round-trip.

Docker Compose a partir de JSON

Pipelines de CI/CD às vezes geram configurações do Docker Compose programaticamente a partir de um armazenamento de configuração JSON e depois as escrevem em disco como YAML para os desenvolvedores lerem.

Armadilha crítica — política de reinicialização:

{"restart_policy": "no"}

No Compose, restart_policy: "no" é um valor válido significando «nunca reiniciar o container». Sem aspas em YAML, isso se torna restart_policy: false, que o Docker Compose pode tratar como a mesma semântica (falsy = sem reinicialização) ou rejeitar com um erro de validação de tipo — o comportamento varia por versão do Compose. As aspas são obrigatórias.

Também fique atento a: o condition: "on-failure" de deploy.restart_policy do Compose v3 — o valor on-failure contém a palavra on, mas está hifenizado e não está na lista de gatilho, então é realmente seguro. No entanto, condition: on (sem o -failure) causaria incompatibilidade. Coloque aspas nos valores de variável de ambiente no bloco environment: se puderem ser palavras Norway.

Valide arquivos Compose após a conversão: docker-compose config analisa e re-emite a forma canônica, revelando erros de tipo.

Workflow do GitHub Actions

Os workflows do GitHub Actions são arquivos YAML editados manualmente por desenvolvedores. O cenário de conversão mais comum é ler dados de workflow da API do GitHub (que retorna JSON) e convertê-los para um arquivo YAML local para edição.

Os campos principais a observar:

# SEGURO — sem palavras Norway nos campos padrão do GitHub Actions
on:                        # "on" é uma chave YAML aqui, não um valor — tratado diferentemente
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: |
          npm install
          npm test
        env:
          NODE_ENV: production   # seguro — não é palavra Norway
          DEBUG: "off"           # palavra Norway no valor — precisa de aspas

Nota: on: como uma chave YAML é especial — o problema Norway se aplica a valores, não a chaves. Mas on como um valor (como DEBUG: on) acionaria a coerção. O bloco env: merece escrutínio particular porque os valores de variável de ambiente são strings, mas muitos deles são flags curtas que poderiam colidir com palavras Norway.

Para workflows que incluem especificações shell:, os valores válidos (bash, pwsh, sh, python) são todos seguros da coerção Norway. Valores personalizados devem ser colocados entre aspas proativamente.

Plano JSON do Terraform → YAML

terraform show -json tfplan > plan.json gera uma representação JSON detalhada do que o Terraform planeja criar, modificar ou destruir. Converter isso para YAML o torna mais legível para revisões de pull request e auditorias de conformidade.

terraform plan -out=tfplan
terraform show -json tfplan > plan.json
# Em seguida, converta com nossa ferramenta ou uma biblioteca

O JSON do plano Terraform é complexo e profundo. Principais preocupações ao converter:

  1. IDs de inteiros grandes. IDs de recursos de nuvem (IDs de conta AWS, números de projeto GCP) e valores de atributos computados podem ser números grandes. Converta via Python ou Go para evitar perda de precisão de float64.

  2. Strings de restrição de versão. O Terraform usa ~>, >=, <= em restrições de versão de provedor. Esses são valores de string que o YAML trata corretamente desde que não sejam palavras Norway — mas ~> é seguro.

  3. Valores de configuração de provedor. As saídas do plano Terraform podem incluir valores de configuração para recursos. Se um campo booleano padrão para false e for representado como "no" em algum schema de provedor, esse é um risco Norway no caminho de volta para YAML.

  4. O bloco .sensitive_values. Valores sensíveis são redigidos como booleanos true no JSON do plano. Estes sobrevivem à conversão de forma limpa, já que true não é uma palavra Norway em nenhuma versão do YAML.

A conversão de Terraform para YAML é principalmente para revisão humana, não para realimentar o Terraform. Não use manifestos YAML como entrada do Terraform — o formato nativo do Terraform é HCL, e seu formato de entrada JSON é específico e documentado separadamente.

Exemplos de Código — 4 Linguagens

Node.js (eemeli/yaml + js-yaml)

O ecossistema Node.js tem duas bibliotecas YAML dominantes com tratamento do Norway significativamente diferente:

// eemeli/yaml — recomendado, YAML 1.2 por padrão, seguro ao Norway
import { stringify } from 'yaml';
import { readFileSync } from 'fs';

const jsonInput = readFileSync('input.json', 'utf8');
const data = JSON.parse(jsonInput);

// Padrão: YAML 1.2 — "NO" fica como "NO", sem coerção booleana
const yamlOutput = stringify(data);
console.log(yamlOutput);
// region: NO      ← seguro no 1.2, mas para compatibilidade máxima use aspas explícitas

// Forçar comportamento YAML 1.1 (para ambientes K8s/Helm que analisam 1.1)
const yamlForK8s = stringify(data, { version: '1.1' });
// region: 'NO'    ← entre aspas automaticamente porque 1.1 interpretaria NO como false
console.log(yamlForK8s);
// js-yaml — amplamente usado, mas semântica YAML 1.1, arriscado ao Norway sem cuidado
import yaml from 'js-yaml';
import { readFileSync } from 'fs';

const data = JSON.parse(readFileSync('input.json', 'utf8'));

// Dump padrão — palavras Norway podem não ter aspas
const unsafe = yaml.dump(data);
// region: NO    ← será interpretado como false se relido por um parser 1.1!

// Mais seguro: use um schema personalizado ou force aspas
const safer = yaml.dump(data, {
  schema: yaml.JSON_SCHEMA,   // restringe a tipos compatíveis com JSON
  noCompatMode: false,
  lineWidth: -1,
  quotingType: '"',
  forceQuotes: false,         // apenas coloca aspas quando necessário por esquema JSON
});

Para novos projetos, prefira eemeli/yaml. Seu padrão YAML 1.2 é mais seguro, sua API de Documento dá controle detalhado sobre aspas, e trata melhor a fidelidade de round-trip. Para projetos já usando js-yaml, use a opção JSON_SCHEMA para restringir a tipos seguros para JSON. Para uma análise mais aprofundada de filtrar e transformar JSON antes da conversão, veja o guia de linha de comando jq para padrões de pré-processamento.

Python (PyYAML + ruamel.yaml)

Python é a linguagem dominante para ferramentas Kubernetes, Ansible e pipelines de engenharia de dados — todos grandes usuários de YAML.

import json
import yaml
import sys

# PyYAML — simples, padrão, mas YAML 1.1 por padrão
with open('input.json') as f:
    data = json.load(f)

output = yaml.dump(data, default_flow_style=False, allow_unicode=True)
# country: 'NO'   ← PyYAML é esperto o suficiente para colocar aspas automáticas em palavras Norway
# Mas NÃO coloca aspas em "yes", "no" (minúsculas) em todas as configurações:
# enabled: 'yes'   ← entre aspas
# tag: y           ← pode ou não ter aspas dependendo da versão

print(output)
import json
import sys
from ruamel.yaml import YAML

# ruamel.yaml — fidelidade de round-trip, suporta YAML 1.2, recomendado para produção
yaml_rt = YAML()
yaml_rt.default_flow_style = False
yaml_rt.width = 4096              # previne quebra de linha indesejada
yaml_rt.best_map_flow_style = False

with open('input.json') as f:
    data = json.load(f)

yaml_rt.dump(data, sys.stdout)
# Preserva a ordem das chaves, trata palavras Norway corretamente, suporta âncoras no round-trip

Para scripts de automação do Ansible e Kubernetes onde você está convertendo respostas de API JSON para manifestos YAML, ruamel.yaml é a escolha mais segura. PyYAML é adequado para scripts simples onde você controla os dados de entrada e verificou que nenhuma palavra Norway aparece.

Se você usa arquivos de configuração JSON5 ou JSONC (com comentários) antes da conversão, remova as extensões primeiro — veja o guia de formatação JSON5 e JSONC para parsers compatíveis.

Go (gopkg.in/yaml.v3)

Go é a linguagem do próprio ecossistema Kubernetes — kubectl, Helm, Argo, Flux e a maioria dos operadores K8s são escritos em Go.

package main

import (
    "encoding/json"
    "fmt"
    "os"

    "gopkg.in/yaml.v3"
)

func main() {
    // Lê entrada JSON
    jsonBytes, err := os.ReadFile("input.json")
    if err != nil {
        panic(err)
    }

    // Unmarshal JSON em um mapa genérico
    var data map[string]interface{}
    if err := json.Unmarshal(jsonBytes, &data); err != nil {
        panic(err)
    }

    // Marshal para YAML — yaml.v3 usa semântica YAML 1.2
    yamlBytes, err := yaml.Marshal(data)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(yamlBytes))
    // country: "NO"     ← yaml.v3 coloca aspas em palavras Norway corretamente
    // replicas: 3       ← inteiros permanecem inteiros
    // enabled: true     ← booleanos permanecem booleanos
}

yaml.v3 é uma melhoria significativa em relação a yaml.v2 para segurança contra Norway. A biblioteca v2 seguia YAML 1.1 e escrevia NO sem aspas; a v3 coloca aspas em valores ambíguos corretamente. Se você está mantendo um projeto Go mais antigo que usa v2, atualize para v3 — a API é em grande parte compatível e a melhoria de segurança vale a migração.

Para conversão com segurança de tipos usando structs Go (em vez de map[string]interface{}), use tags de struct:

type DeploymentLabels struct {
    App    string `yaml:"app" json:"app"`
    Region string `yaml:"region" json:"region"`
}
// yaml.Marshal em um campo de struct contendo "NO" irá colocá-lo entre aspas corretamente no v3

CLI Bash (yq + jq)

Para scripts shell e conversões rápidas pontuais, yq (versão de Mike Farah, mikefarah/yq) converte JSON para YAML em um único comando:

# Instalar yq
brew install yq                         # macOS
sudo wget -qO /usr/local/bin/yq \
  https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
chmod +x /usr/local/bin/yq              # Linux

# Converter arquivo JSON para YAML
yq -P < input.json > output.yaml

# Converter a partir de saída JSON do kubectl
kubectl get deploy my-app -o json | yq -P > manifest.yaml

# Redirecionar pelo jq primeiro para filtrar/transformar, depois converter para YAML
kubectl get deploy my-app -o json \
  | jq 'del(.status, .metadata.creationTimestamp, .metadata.managedFields)' \
  | yq -P > clean-manifest.yaml

O pipeline jq | yq é um padrão poderoso: use jq para manipulação de JSON (filtrar campos, remodelar estrutura, consultar valores) e yq -P como o serializador YAML final. Para padrões jq, veja o guia de linha de comando jq com 30 padrões do mundo real incluindo integrações com kubectl e aws.

Cautela Norway com yq: o yq (mikefarah) respeita o tipo de entrada do JSON — uma string JSON "NO" na entrada será serializada como uma string YAML com aspas. Mas se você gerar YAML diretamente com yq (não a partir de entrada JSON), deve colocar aspas explicitamente em valores que sejam palavras Norway. Use nosso conversor YAML para JSON para validar o round-trip após a saída do yq.

Casos Extremos e Pegadinhas

Além do problema Norway, a conversão JSON ↔ YAML tem vários casos extremos que pegam engenheiros experientes de surpresa:

  1. YAML com múltiplos documentos (separador ---). Um único arquivo YAML pode conter múltiplos documentos separados por ---. JSON não tem conceito equivalente. Ao converter YAML com múltiplos documentos para JSON, a maioria das ferramentas toma apenas o primeiro documento, mescla todos os documentos em um array ou retorna um erro. Ao converter JSON para YAML, um único cabeçalho de documento --- é adicionado por convenção. Decida e documente seu comportamento explicitamente para pipelines que possam encontrar arquivos com múltiplos documentos.

  2. Âncoras e aliases YAML. O YAML suporta definições &anchor e referências *alias para configurações DRY. Ao converter YAML para JSON, as âncoras devem ser expandidas — o JSON resultante pode ser muito maior que o YAML fonte. Ao converter JSON para YAML, o conversor não pode reconstruir âncoras que não existiam no original. Aliases são uma funcionalidade exclusiva do YAML.

  3. Análise implícita de timestamps. Parsers YAML 1.1 convertem 2024-05-04 e 2024-05-04T12:00:00Z para objetos de data nativos da linguagem, não strings. Quando esse objeto de data é serializado de volta para JSON, a saída depende da biblioteca: algumas geram strings ISO, algumas geram timestamps Unix, algumas geram null. Fazer round-trip de datas pelo YAML sem aspas explícitas de string ("2024-05-04") pode silenciosamente mudar o formato.

  4. A tag !!binary. O YAML pode incorporar dados binários codificados em base64 com a tag !!binary. O JSON não tem tipo binário — binário deve ser uma string base64. Ao converter YAML com campos !!binary para JSON, decodifique para string base64. Ao converter de volta, você não pode reconstruir a tag binária sem conhecer o schema. O Kubernetes usa !!binary para alguns valores de secret.

  5. Colisões de tipo de chave. JSON exige que as chaves de objeto sejam strings. O YAML permite chaves de qualquer tipo — chaves inteiras, chaves booleanas, até mesmo chaves de objeto complexas. Um arquivo YAML com true: value ou 1: value como chaves não pode ser fielmente representado como JSON. A maioria dos conversores transforma as chaves em strings, mas a semântica muda.

  6. Variância de representação de null. Em YAML, null, ~, Null, NULL e um valor vazio todos significam null. Em JSON, apenas null é null. Ao converter YAML para JSON, todos esses se normalizam para null. Mas ao converter JSON de volta para YAML, a escolha de representação de null importa — ~ é mais compacto, null é mais explícito. Escolha um e mantenha a consistência.

  7. Mudanças de ordem de classificação. Objetos JSON tecnicamente não têm ordem de chave definida (embora a maioria dos parsers preserve a ordem de inserção). Mapeamentos YAML da mesma forma não têm ordem obrigatória. Mas algumas bibliotecas YAML ordenam as chaves alfabeticamente por padrão ao serializar. Isso pode causar grandes diffs no controle de versão se o JSON fonte usou uma ordem diferente. Configure sort_keys=False no PyYAML (default_flow_style=False sozinho não previne a ordenação) e opções equivalentes em outras bibliotecas.

Quando NÃO Converter

A conversão nem sempre é a resposta certa. Aqui estão os cenários onde permanecer no formato original é a melhor escolha:

Não converta YAML para JSON se o YAML contiver comentários que documentam lógica de negócios. Comentários YAML não fazem parte do modelo de dados — eles desaparecem em qualquer serialização para JSON. Se um manifesto do Kubernetes tem comentários explicando por que um limite de recurso específico foi escolhido ou por que uma exceção de política de segurança foi feita, converter para JSON destrói essa documentação. Mantenha o YAML.

Não converta automaticamente configurações em pipelines de CI sem testes de round-trip. Se seu pipeline converte JSON para YAML e depois aplica o YAML a um cluster, adicione um passo de validação de round-trip: YAML de volta para JSON, depois compare com o original. Isso detecta surpresas de coerção de tipo antes de chegarem à produção.

Não converta apenas porque uma ferramenta gera JSON. kubectl, aws, terraform e docker inspect todos geram JSON, mas a maioria dessas ferramentas também aceita YAML como entrada. Antes de construir um passo de conversão, verifique se a ferramenta de destino pode aceitar diretamente entrada YAML — a maioria das ferramentas DevOps modernas pode. Nosso conversor YAML para JSON é mais útil quando você especificamente precisa de JSON para uma ferramenta que não aceita YAML.

Não converta se os schemas forem diferentes. Se seu JSON usa chaves camelCase e seu consumidor YAML espera snake_case (ou vice-versa), você precisa de um passo de transformação além de uma conversão de formato. Uma conversão de formato puro produzirá YAML sintaticamente correto, mas semanticamente errado. Trate o mapeamento de schema explicitamente.

Não mantenha ambos os formatos em sincronia manualmente. Se você está mantendo um config.json e um config.yaml que deveriam ser equivalentes, você vai divergir. Escolha um formato canônico e derive o outro automaticamente — ou melhor, escolha um formato e elimine a duplicação.

FAQ

O problema Norway do YAML ainda afeta sistemas modernos?

Sim — é generalizado no ecossistema. Kubernetes e Helm usam a biblioteca yaml.v2 do Go (semântica YAML 1.1) em partes significativas de suas bases de código. Ansible usa PyYAML (YAML 1.1). Workflows do GitHub Actions são analisados pelo parser YAML interno do GitHub, que tem seu próprio comportamento. A maioria dos arquivos YAML de CI/CD existentes é processada por parsers YAML 1.1. Assuma semântica 1.1 até que tenha verificado o contrário.

Por que eu converteria JSON para YAML se YAML é mais difícil de analisar?

A conversão não é sobre dificuldade do parser — é sobre editabilidade humana. JSON é ideal para máquinas; YAML é ideal para humanos que precisam ler, editar e revisar arquivos de configuração. Um manifesto do Kubernetes commitado no git, revisado em pull requests e ajustado manualmente por engenheiros deve ser YAML. O mesmo manifesto recuperado da API para processamento programático deve ser JSON. Nosso conversor JSON para YAML faz a ponte entre os dois.

Posso fazer round-trip JSON ↔ YAML sem perda?

Com ressalvas, sim — para dados compatíveis com JSON. JSON é um subconjunto do YAML 1.2, então qualquer documento JSON válido é YAML 1.2 válido. Ir de JSON → YAML → JSON deve ser sem perda para quaisquer dados sem coerção de tipo implícita. O problema Norway significa que uma string JSON "NO" poderia sobreviver ao passo de ida apenas se o conversor a colocar entre aspas, e depois sobreviver ao passo de volta apenas se o parser YAML respeitar as aspas. Use uma biblioteca YAML 1.2 para ambas as direções para garantir round-trips sem perda.

Qual é a biblioteca YAML mais segura para produção?

Para Python: ruamel.yaml configurado para YAML 1.2. Para Node.js: eemeli/yaml (o pacote yaml no npm). Para Go: gopkg.in/yaml.v3. Todas as três implementam semântica YAML 1.2 ou têm modos YAML 1.2 explícitos e tratam palavras Norway corretamente. Evite bibliotecas YAML 1.1 em novos projetos. Se você deve usar uma biblioteca 1.1 (PyYAML, js-yaml, yaml.v2) por razões de compatibilidade, sempre coloque aspas explicitamente em strings propensas ao Norway.

Os manifestos YAML do Kubernetes suportam comentários após conversão JSON?

Não — comentários não podem ser recuperados do JSON. JSON não tem sintaxe de comentário, então não há nada a converter. Quando você executa kubectl get deploy -o json e converte a saída para YAML para armazenamento no git, o YAML resultante não terá comentários. Comentários em um manifesto do Kubernetes devem ser escritos por um humano após a conversão. Essa é uma das razões pelas quais manter o YAML criado manualmente como a fonte canônica é frequentemente preferível a fazer round-trip pela API JSON.

Como lidar com inteiros grandes como resourceVersion ou timestamps em nanosegundos?

O metadata.resourceVersion do Kubernetes é um campo de string deliberadamente — a equipe do Kubernetes sabia que parsers JSON em JavaScript e outros runtimes baseados em float64 perderiam precisão em inteiros grandes. Sempre trate-o como uma string. Para inteiros grandes genuinamente numéricos (como timestamps de época em nanosegundos em alguns sistemas de rastreamento), use o tipo int do Python, int64 do Go ou BigInt do Node.js para análise. Nunca os passe pelo JSON.parse() do JavaScript sem uma função reviver personalizada. Ao converter para YAML, esses inteiros grandes são seguros — YAML não tem limite de precisão para inteiros. O perigo está no round-trip de volta pelo parser JSON do JavaScript.

O YAML 1.2 é amplamente adotado agora?

De forma desigual. As principais bibliotecas de linguagem têm migrado: yaml.v3 do Go, ruamel.yaml do Python e eemeli/yaml do Node.js todas suportam ou usam por padrão YAML 1.2. Mas Kubernetes, Ansible e grande parte do ecossistema DevOps ainda rodam em parsers YAML 1.1 devido ao custo de compatibilidade retroativa da migração. A adoção de YAML 1.2 em novos projetos é recomendada, mas assuma 1.1 para qualquer sistema que você não configurou.

Nossa equipe deve padronizar em JSON ou YAML para configurações?

Padronize com propósito, não com formato. Use JSON para configurações consumidas por código (corpos de requisição de API, arquivos de configuração de SDK, ferramentas programáticas). Use YAML para configurações consumidas por humanos (manifestos do Kubernetes, pipelines de CI, configurações de deploy, playbooks do Ansible). Evite misturar os dois para a mesma configuração — escolha uma representação por tipo de configuração e automatize a conversão se precisar de ambas. Quando precisar converter, tanto nosso conversor JSON para YAML quanto o conversor YAML para JSON rodam inteiramente no seu navegador — nenhum dado sai do dispositivo.

Experimente Agora

Pronto para converter um arquivo real? Experimente nosso conversor JSON para YAML para transformar JSON em YAML seguro para o Kubernetes — ele coloca aspas automaticamente em palavras Norway (NO, yes, on, off e a lista completa de booleanos YAML 1.1) e permite que você escolha indentação de 2 ou 4 espaços. Para a direção inversa, nosso conversor YAML para JSON trata âncoras, aliases e YAML com múltiplos documentos. Ambas as ferramentas rodam inteiramente no seu navegador — seus dados nunca saem do dispositivo, o que importa quando você está trabalhando com manifestos do Kubernetes em produção ou planos do Terraform que contêm configurações de recursos sensíveis.

Artigos relacionados

Ver todos os artigos