Masalah Norway YAML dan Perbedaan JSON ↔ YAML yang Harus Diketahui Engineer
Itu adalah deployment Helm yang rutin. Tim telah menghabiskan dua hari menyempurnakan file values.yaml untuk rollout multi-region. Chart tersebut men-template sebuah Kubernetes ConfigMap dengan metadata locale — termasuk kode negara untuk pusat data Norwegia mereka. Seseorang mengetik country: NO dan meng-commit-nya. Pipeline CI berjalan hijau. Deployment berjalan.
Kemudian alert masuk.
ConfigMap berisi country: false alih-alih country: "NO". Setiap layanan hilir yang membaca field country mendapatkan boolean alih-alih string. Perbandingan string gagal. Logika routing jatuh ke default. Traffic yang seharusnya tetap di Norwegia malah diproses oleh endpoint regional yang salah.
Akar masalahnya adalah satu string tanpa kutip dalam file YAML. YAML 1.1 — versi yang digunakan hampir semua tooling Kubernetes — memperlakukan NO sebagai boolean false. Ia memperlakukan YES, ON, OFF, Y, N, no, yes, on, off, y, n, dan selusin varian lainnya dengan cara yang sama. Tanpa peringatan. Tanpa error. Diam-diam salah.
JSON tidak memiliki masalah ini. {"country": "NO"} selalu berupa string. Konversi tipe implisit YAML adalah kenyamanan terbesar sekaligus jebakan paling berbahaya.
Panduan ini mencakup gambaran lengkap: mengapa masalah Norway ada, apa yang berubah di YAML 1.2 (dan mengapa sebagian besar tooling mengabaikannya), cara menulis strategi pengutipan yang benar, aturan indentasi yang sering membingungkan pemula, jebakan presisi angka, dan empat skenario konversi dunia nyata mulai dari manifest Kubernetes hingga Terraform plan. Ketika Anda perlu secara aman meratakan nilai JSON ke YAML tanpa jebakan ini, konverter JSON ke YAML kami secara otomatis mengutip string yang bermasalah dengan Norway.
JSON vs YAML — Kapan Menggunakan Yang Mana
Sebelum menyelami masalah Norway, penting untuk memahami apa yang sebenarnya dioptimalkan oleh masing-masing format. Keduanya tidak dapat dipertukarkan — masing-masing memiliki pusat desain yang menjadikannya pilihan lebih baik dalam konteks tertentu.
| Dimensi | JSON | YAML |
|---|---|---|
| Sintaks | Ketat — kurung kurawal, kutipan, koma wajib | Fleksibel — berbasis indentasi, tanda baca minimal |
| Sistem tipe | Eksplisit: string, angka, boolean, null, array, objek | Implisit — YAML 1.1 menyimpulkan tipe dari bentuk nilai |
| Keterbacaan manusia | Ramah developer, dapat diverifikasi mesin | Ramah manusia, mudah diedit tangan |
| Kebutuhan kutipan | String selalu dikutip | Sebagian besar scalar dapat tanpa kutipan (sumber masalah Norway) |
| Komentar | Tidak didukung | Didukung dengan # |
| Penggunaan utama | API, pertukaran data, sistem konfigurasi modern | Kubernetes, Docker Compose, Ansible, pipeline CI |
| Parse mengejutkan | Tidak ada — parsing ketat | Ya — Norway, oktal, timestamp |
| Penegakan skema | Ekosistem JSON Schema | YAML Schema (tooling lebih sedikit) |
JSON menang ketika data Anda melintasi batas sistem — REST API, antrian pesan, serialisasi database. Mesin mem-parsing-nya, mesin menghasilkannya, dan sintaks yang ketat membuat validasi mudah. Gunakan JSON Formatter untuk memvalidasi struktur sebelum mengirim.
YAML menang ketika manusia adalah penulis utama. Manifest Kubernetes, workflow GitHub Actions, chart Helm, playbook Ansible — ini adalah file yang dibaca dan diedit developer puluhan kali. Tanda baca yang berkurang dan dukungan untuk komentar membuatnya benar-benar lebih mudah dipelihara daripada padanan JSON-nya.
Masalah muncul di batas: ketika sebuah alat menghasilkan JSON (seperti kubectl get deploy -o json atau terraform show -json) dan manusia perlu mengontrol versi atau mengedit hasilnya sebagai YAML. Konversi itulah tempat masalah Norway berada. Konverter YAML ke JSON kami menangani arah sebaliknya ketika Anda perlu kembali.
Masalah Norway — Pembahasan Mendalam
Masalah Norway bukan bug. Ini adalah fitur spesifikasi YAML 1.1 yang berperilaku persis seperti yang dirancang. Memahami mengapa ia dirancang demikian — dan mengapa begitu banyak sistem masih mengimplementasikan 1.1 — adalah kunci untuk menghindarinya.
Mengapa “no”, “yes”, “on”, “off”, “y”, “n” Diparsing Salah
Spesifikasi YAML 1.1 mendefinisikan tipe boolean yang luas yang dimaksudkan untuk ramah manusia. Ia mengenali semua hal berikut sebagai true atau false:
True: y, Y, yes, Yes, YES, true, True, TRUE, on, On, ON
False: n, N, no, No, NO, false, False, FALSE, off, Off, OFF
Niatnya baik: file konfigurasi sering menggunakan yes/no alih-alih true/false dalam bahasa Inggris, dan YAML ingin mendukung cara alami orang menulis konfigurasi. Masalahnya adalah yes, no, on, off, y, dan n juga merupakan nilai string yang sah yang memiliki arti yang sama sekali berbeda di sebagian besar aplikasi.
Berikut ketidaksesuaian dalam YAML konkret:
# YAML 1.1 (yang diimplementasikan sebagian besar parser)
country: NO # diparsing sebagai: country: false ← BAHAYA
enabled: yes # diparsing sebagai: enabled: true
restart: off # diparsing sebagai: restart: false
language: y # diparsing sebagai: language: true
shell: n # diparsing sebagai: shell: false
# Benar — tanda kutip string eksplisit mengesampingkan inferensi tipe
country: "NO" # diparsing sebagai: country: "NO" ← aman
enabled: "yes" # diparsing sebagai: enabled: "yes"
restart: "off" # diparsing sebagai: restart: "off"
language: "y" # diparsing sebagai: language: "y"
shell: "n" # diparsing sebagai: shell: "n"
Dan perbandingan JSON:
{"country": "NO"}
Dalam JSON, NO di dalam kutipan selalu dan tanpa syarat merupakan string. Tidak ada inferensi tipe implisit. Ketegasan yang membuat JSON terasa verbose juga yang membuatnya aman.
Di luar konversi boolean, YAML 1.1 juga secara implisit mengonversi:
123e4→ angka1230000(notasi ilmiah)0x1A→ angka26(heksadesimal)0755→ angka493(oktal — ini merusak string izin file Unix)2024-05-04→ objek tanggal di banyak parser (bukan hanya string)1_000_000→ angka1000000(pemisah garis bawah)
Masalah Norway sebenarnya hanyalah anggota paling terkenal dari seluruh keluarga konversi tipe implisit YAML.
YAML 1.1 vs 1.2 — Apa yang Berubah
YAML 1.2 diterbitkan pada 2009 — empat tahun setelah YAML 1.1. Tujuan utamanya adalah membawa YAML ke keselarasan ketat dengan JSON (karena JSON sebenarnya merupakan subset YAML 1.2 yang valid) dan mengurangi konversi tipe implisit yang mengejutkan.
Dalam YAML 1.2:
- Boolean dipersempit menjadi tepat
truedanfalse(peka huruf besar-kecil). Hanya itu.yes,no,on,offadalah string biasa. - Literal oktal memerlukan prefiks
0o(0o755) — bentuk lama0755adalah string. - Timestamp tidak diparsing secara implisit —
2024-05-04tetap menjadi string kecuali Anda menandainya secara eksplisit. - Spesifikasi itu sendiri adalah superset JSON, artinya setiap dokumen JSON yang valid adalah YAML 1.2 yang valid.
Di atas kertas, YAML 1.2 sepenuhnya menyelesaikan masalah Norway. Dalam praktiknya, ekosistem hampir tidak bergerak.
| Library | Spesifikasi default | Risiko Norway |
|---|---|---|
| PyYAML (Python) | YAML 1.1 | Ya — yaml.safe_load masih mem-parsing NO sebagai False |
| ruamel.yaml (Python) | YAML 1.2 (opsional) | Dapat dikonfigurasi — lebih aman secara default |
| js-yaml (Node.js) | YAML 1.1 | Ya di versi lama; versi baru memiliki opsi FAILSAFE_SCHEMA |
| eemeli/yaml (Node.js) | YAML 1.2 | Tidak — 1.2 secara default, atau dapat dipilih secara eksplisit |
| gopkg.in/yaml.v2 (Go) | YAML 1.1 | Ya |
| gopkg.in/yaml.v3 (Go) | YAML 1.2 | Jauh lebih aman |
| Kubernetes / Helm | YAML 1.1 (via Go yaml.v2) | Ya — historis, sangat sulit dimigrasikan |
| Ansible | YAML 1.1 (via PyYAML) | Ya |
Alasan migrasi lambat adalah kompatibilitas mundur. Sistem yang telah mengandalkan yes/no diparsing sebagai boolean selama satu dekade tidak dapat secara diam-diam mengubah perilaku itu tanpa merusak konfigurasi yang ada. Kubernetes khususnya memiliki basis instalasi yang sangat besar di mana mengubah semantik parsing YAML akan menjadi perubahan breaking di seluruh cluster.
Kesimpulan praktis: asumsikan semantik YAML 1.1 di alat mana pun yang tidak Anda konfigurasi secara eksplisit. Selalu kutip string yang bisa salah dibaca sebagai boolean, timestamp, atau angka.
Bagaimana Sistem Produksi Terdampak
Kode negara Norway adalah contoh yang paling sering dikutip karena tidak intuitif — NO terlihat seperti singkatan yang jelas, bukan boolean. Tetapi pola ini berulang di banyak skenario dunia nyata:
Kode bandara IATA. Bandara Norwegia Harstad/Narvik memiliki kode EVE. Aman. Oslo Gardermoen adalah OSL. Juga aman. Tetapi aplikasi mana pun yang menggunakan YAML untuk menyimpan kode bandara regional hanya satu kode rute no dari boolean false di produksi.
Nama variabel environment. ON adalah nilai variabel environment yang sah yang berarti “diaktifkan” di beberapa sistem lama. OFF adalah padanannya. Memigrasikan konfigurasi dari shell script ke YAML tanpa mengutip nilai-nilai ini memperkenalkan konversi tipe diam-diam.
Field pengguna email. Pengguna yang nama depan atau username-nya adalah n, y, atau salah satu kata pemicu akan diserialisasi secara tidak benar jika aplikasi membuang YAML tanpa pengutipan yang tepat. Ini sangat berbahaya karena hanya gagal untuk sebagian kecil pengguna.
Kebijakan restart Docker Compose. Nilai field restart_policy yaitu "no" berarti “jangan restart.” Jika kutipannya hilang dalam round-trip YAML, nilainya menjadi false, dan Docker Compose mungkin mengartikannya sebagai “tidak ada kebijakan restart yang ditentukan” atau melempar error validasi — bagaimanapun, perilaku restart container salah.
Field shell: GitHub Actions. Nilai shell yang valid adalah bash, pwsh, python, sh, cmd, powershell. Tidak ada yang merupakan kata Norway. Tetapi seseorang yang mengetik shell: yes atau shell: on sebagai placeholder selama pengeditan draft mungkin terkejut ketika YAML mengubahnya menjadi boolean sebelum validator bahkan melihatnya.
Perbaikan di semua kasus adalah sama: kutip string yang secara semantis merupakan string, terlepas dari apakah manusia akan mengenalinya sebagai kata kunci. Konverter JSON ke YAML kami menerapkan ini secara otomatis — nilai mana pun dalam daftar kata Norway dikutip di output.
Strategi Pengutipan String
Setelah Anda memahami mengapa kata Norway tidak cocok, solusinya adalah memilih strategi pengutipan yang tepat untuk kasus penggunaan Anda. YAML mendukung tiga mode, masing-masing dengan tradeoff yang berbeda.
Auto vs Double vs Single
Pengutipan Auto (direkomendasikan untuk sebagian besar konversi) membiarkan library memutuskan kapan kutipan diperlukan. Nilai yang akan salah dibaca tanpa kutipan — kata Norway, angka, timestamp, string yang terlihat seperti sintaks YAML — dikutip secara otomatis. Semua yang lain tetap sebagai scalar biasa. Ini menghasilkan output yang paling mudah dibaca sekaligus tetap aman.
# Output mode Auto
name: Alice # biasa — tidak ambigu
country: "NO" # dikutip — kata Norway
age: 30 # biasa — angka tidak ambigu
created: "2024-05-04" # dikutip — jika tidak akan diparsing sebagai tanggal
port: "8080" # tergantung library — beberapa mengutip string yang terlihat numerik
String tanda kutip ganda membungkus semua nilai string dalam tanda kutip ganda. Ini eksplisit dan dapat diaudit — pembaca mana pun dapat melihat bahwa semua nilai ini adalah string tanpa perlu memikirkan spesifikasinya. Tradeoffnya adalah verbositas dan berkurangnya keterbacaan manusia, terutama untuk konfigurasi yang sangat bertingkat.
# Mode tanda kutip ganda
name: "Alice"
country: "NO"
replicas: "3" # bahkan angka menjadi string — mungkin menyebabkan error skema
Hati-hati: jika skema target Anda mengharapkan angka dan Anda menserialisasinya sebagai string yang dikutip, parser YAML akan mengetiknya dengan benar sebagai string, tetapi Kubernetes atau konsumen ketat lainnya mungkin menolak field tersebut sebagai tipe yang salah.
String tanda kutip tunggal adalah fitur khusus YAML — JSON tidak memiliki sintaks tanda kutip tunggal. Tanda kutip tunggal bersifat literal: tidak ada urutan escape di dalamnya. Satu-satunya kasus khusus adalah tanda kutip tunggal di dalam string tanda kutip tunggal harus digandakan (''). Tanda kutip tunggal ideal untuk string yang mengandung backslash atau karakter khusus yang perlu di-escape dalam tanda kutip ganda.
# Mode tanda kutip tunggal
pattern: 'C:\Users\alice\Documents' # tidak perlu escape
regex: '\d+\.\d+' # backslash literal
Untuk konversi JSON-ke-YAML yang dimaksudkan untuk round-trip kembali ke JSON, lebih suka mode Auto atau Double. String tanda kutip tunggal memperkenalkan sintaks khusus YAML yang memerlukan parser yang mengenali YAML dalam perjalanan kembali.
Block Scalar (| dan >)
Sintaks block scalar YAML benar-benar berguna untuk string multi-baris — sesuatu yang ditangani JSON dengan canggung menggunakan urutan escape \n.
Block scalar literal | mempertahankan newline secara tepat:
# Block literal — newline dipertahankan
script: |
#!/bin/bash
set -euo pipefail
echo "Starting deployment"
kubectl apply -f manifest.yaml
# Representasi JSON yang setara (tidak terbaca)
# {"script": "#!/bin/bash\nset -euo pipefail\necho \"Starting deployment\"\nkubectl apply -f manifest.yaml\n"}
Block scalar folded > menggabungkan baris dengan spasi, mengubah setiap newline menjadi spasi (kecuali baris kosong, yang menjadi newline):
# Block folded — newline menjadi spasi
description: >
Layanan ini menangani autentikasi
untuk seluruh platform. Ia mendukung
OAuth2, SAML, dan autentikasi API key.
# Hasil: "Layanan ini menangani autentikasi untuk seluruh platform. Ia mendukung OAuth2, SAML, dan autentikasi API key.\n"
Block scalar bersinar untuk menyematkan sertifikat TLS, shell script multi-baris, atau query SQL dalam konfigurasi YAML — skenario di mana padanan JSON-nya adalah one-liner panjang yang di-escape yang tidak dapat dibaca manusia mana pun.
Saat mengonversi dari JSON ke YAML, sebagian besar konverter (termasuk milik kami) menggunakan mode Auto dan merepresentasikan string multi-baris dengan block scalar hanya ketika mendeteksi newline yang disematkan. String satu baris mendapatkan flow scalar (dikutip atau biasa). Gunakan konverter JSON ke YAML kami untuk melihat output sebelum meng-commit-nya ke manifest.
Indentasi — 2 vs 4 Spasi, Tab Dilarang
Aturan indentasi YAML lebih ketat dari yang terlihat. Spesifikasi memiliki satu aturan absolut dan satu konvensi yang bervariasi menurut ekosistem.
Aturan absolut: tab dilarang. Setiap level indentasi harus menggunakan spasi. Karakter tab dalam file YAML adalah error parse di sebagian besar parser:
# SALAH — tab menyebabkan error parse
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app # ← karakter tab di sini → ParseError
# BENAR — hanya spasi
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app # ← dua spasi
Pesan error yang akan Anda lihat bervariasi menurut library. Di PyYAML Python:
yaml.scanner.ScannerError: while scanning for the next token
found character '\t' that cannot start any token
Di yaml.v3 Go:
yaml: line 4: found character that cannot start any token
Konfigurasikan editor Anda untuk memperluas tab menjadi spasi untuk file YAML. Di VS Code, tambahkan ke pengaturan workspace Anda: "[yaml]": { "editor.insertSpaces": true, "editor.tabSize": 2 }.
Konvensi: 2 vs 4 spasi. Keduanya valid. Konvensi ekosistem berbeda:
| Ekosistem | Konvensi | Alasan |
|---|---|---|
| Manifest Kubernetes | 2 spasi | Dokumen dan contoh resmi menggunakan 2 |
| Chart Helm | 2 spasi | Mengikuti konvensi K8s |
| Docker Compose | 2 spasi | Contoh spesifikasi compose resmi |
| GitHub Actions | 2 spasi | Contoh workflow resmi |
| Playbook Ansible | 2 spasi | Dokumentasi resmi |
| Konfigurasi tradisional | 4 spasi | Sesuai default JSON beautify |
Untuk file apa pun yang akan dikonsumsi oleh Kubernetes atau Docker Compose, gunakan 2 spasi. Untuk file konfigurasi mandiri yang hanya akan dibaca oleh manusia dan tooling kustom, keduanya bisa — cukup konsisten dalam satu file. Konverter JSON ke YAML kami menggunakan indentasi 2 spasi sebagai default dan memungkinkan Anda beralih ke 4 untuk proyek yang lebih menyukainya.
Satu aturan lagi: elemen anak harus diindentasi lebih dari induk mereka, tetapi jumlah spasi tambahan dapat berupa bilangan bulat positif apa pun (1, 2, 3, 4…) — selama konsisten dalam satu blok. Dalam praktiknya, selalu gunakan 2 atau 4 untuk keterbacaan.
Penanganan Angka di JSON ↔ YAML
Kedua format mendukung angka, tetapi edge case-nya cukup berbeda untuk menyebabkan bug produksi.
Kehilangan Presisi untuk Angka Besar
Tipe Number JavaScript adalah float IEEE 754 64-bit. Ia dapat merepresentasikan bilangan bulat secara tepat hingga 2^53 − 1 = 9.007.199.254.740.991. Di luar itu, presisi bilangan bulat hilang:
// Kehilangan presisi JavaScript — ini bukan masalah YAML, tetapi mempengaruhi parsing JSON
JSON.parse('{"v": 9007199254740993}').v
// → 9007199254740992 (3 menjadi 2 — satu bit hilang)
// Aman — dalam rentang 2^53
JSON.parse('{"v": 9007199254740991}').v
// → 9007199254740991 (tepat)
Ini penting untuk konversi JSON-ke-YAML di lingkungan JavaScript karena presisi sudah hilang sebelum serialisasi YAML dimulai. Kubernetes metadata.resourceVersion adalah field string khusus karena versi resource dapat melebihi rentang bilangan bulat aman. Field lain yang terlihat seperti angka kecil — observedGeneration, komponen uid — lebih aman, tetapi field int64 apa pun dalam respons K8s berpotensi terpengaruh.
Solusi:
- Gunakan Python atau Go untuk pipeline konversi yang melibatkan angka besar — keduanya menangani bilangan bulat arbitrer secara native.
- Di Node.js, gunakan parser JSON yang mendukung BigInt:
JSON.parse(text, (_, v) => typeof v === 'number' && !Number.isSafeInteger(v) ? BigInt(v) : v). - Untuk field yang harus round-trip tanpa kehilangan, serialisasikan sebagai string di sumber.
- Saat meninjau YAML yang dikonversi, cari field seperti
resourceVersion,generation, dan nilai turunan timestamp.
Keanehan Oktal & Hex
YAML 1.1 memperlakukan string tertentu yang mirip angka sebagai bilangan bulat non-desimal:
# Kejutan parsing YAML 1.1
permissions: 0755 # diparsing sebagai oktal 493, bukan desimal 755
value: 0x1A # diparsing sebagai hex 26, bukan string "0x1A"
# Perilaku YAML 1.2
permissions: 0755 # tetap sebagai bilangan bulat 755 (desimal) — oktal memerlukan prefiks 0o
permissions: 0o755 # diparsing sebagai oktal 493 di 1.1 dan 1.2
# Aman untuk kedua spesifikasi — kutip nilai dengan awalan nol
permissions: "0755" # selalu string "0755"
Jebakan oktal sangat berbahaya untuk izin file Unix, komponen alamat IP dengan awalan nol (beberapa perangkat jaringan), dan kode numerik apa pun yang menggunakan awalan nol untuk padding (kode pos, kode produk). Selalu kutip nilai-nilai ini saat menulis YAML tangan, atau pastikan konverter Anda mengutipnya — konverter JSON ke YAML kami mendeteksi string numerik dari JSON dan mempertahankan tipe string-nya.
Konversi Dunia Nyata
Masalah Norway dan strategi pengutipan menjadi konkret ketika Anda menerapkannya pada skenario konversi nyata.
Manifest Kubernetes dari JSON
Workflow kanonik: kubectl get deploy my-app -o json memberikan objek langsung sebagai JSON. Anda ingin membersihkannya (hapus status, creationTimestamp, field yang dikelola) dan meng-check-in ke git sebagai manifest YAML.
JSON sumber (disingkat):
{
"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" }
]
}]
}
}
}
}
Output YAML yang diharapkan (dengan perlindungan Norway):
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
labels:
app: my-app
region: "NO" # dikutip — kata 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" # dikutip — kata Norway
- name: ENABLE_FEATURE
value: "yes" # dikutip — kata Norway
Perhatikan bahwa replicas: 3 dibiarkan tanpa kutipan — ini adalah bilangan bulat yang sah yang Kubernetes harapkan sebagai angka. Kata Norway dalam labels dan nilai env dikutip. Konverter naif yang tidak menangani boolean YAML 1.1 akan diam-diam menghasilkan region: false dan value: false.
Setelah mengonversi, validasi dengan: kubectl apply --dry-run=client -f manifest.yaml. Ini menangkap error skema tanpa menyentuh cluster.
Coba konversinya di konverter JSON ke YAML kami — tempel JSON di atas dan lihat output yang aman untuk Norway seketika. Gunakan konverter YAML ke JSON kami untuk memverifikasi round-trip.
Docker Compose dari JSON
Pipeline CI/CD terkadang menghasilkan konfigurasi Docker Compose secara terprogram dari penyimpanan konfigurasi JSON, kemudian menulisnya ke disk sebagai YAML untuk dibaca developer.
Jebakan kritis — kebijakan restart:
{"restart_policy": "no"}
Dalam Compose, restart_policy: "no" adalah nilai yang valid yang berarti “jangan pernah restart container.” Tanpa kutipan dalam YAML, ini menjadi restart_policy: false, yang mungkin diperlakukan Docker Compose sebagai semantik yang sama (falsy = tidak restart) atau ditolak dengan error validasi tipe — perilakunya bervariasi menurut versi Compose. Pengutipan wajib.
Juga perhatikan: Compose v3 deploy.restart_policy.condition: "on-failure" — nilai on-failure mengandung kata on, tetapi dengan tanda hubung dan tidak ada dalam daftar pemicu, sehingga sebenarnya aman. Namun, condition: on (tanpa -failure) akan tidak cocok. Kutip nilai variabel environment di blok environment: jika bisa menjadi kata Norway.
Validasi file Compose setelah konversi: docker-compose config mem-parsing dan mengeluarkan ulang bentuk kanonik, memunculkan error tipe.
Workflow GitHub Actions
Workflow GitHub Actions adalah file YAML yang diedit tangan oleh developer. Skenario konversi paling umum adalah membaca data workflow dari GitHub API (yang mengembalikan JSON) dan mengonversinya ke file YAML lokal untuk diedit.
Field utama yang perlu diperhatikan:
# AMAN — tidak ada kata Norway dalam GitHub Actions standar
on: # "on" di sini adalah kunci YAML, bukan nilai — ditangani berbeda
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 # aman — bukan kata Norway
DEBUG: "off" # kata Norway dalam nilai — perlu dikutip
Catatan: on: sebagai kunci YAML bersifat khusus — masalah Norway berlaku untuk nilai, bukan kunci. Tetapi on sebagai nilai (seperti DEBUG: on) akan memicu konversi. Blok env: patut mendapat perhatian khusus karena nilai variabel environment adalah string, tetapi banyak di antaranya adalah flag pendek yang bisa bertabrakan dengan kata Norway.
Untuk workflow yang menyertakan spesifikasi shell:, nilai yang valid (bash, pwsh, sh, python) semuanya aman dari konversi Norway. Nilai kustom harus dikutip secara proaktif.
Terraform JSON Plan → YAML
terraform show -json tfplan > plan.json menghasilkan representasi JSON terperinci tentang apa yang Terraform rencanakan untuk dibuat, dimodifikasi, atau dihancurkan. Mengonversi ini ke YAML membuatnya lebih mudah dibaca untuk review pull request dan audit kepatuhan.
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
# Kemudian konversi dengan alat kami atau library
JSON plan Terraform kompleks dan dalam. Perhatian utama saat mengonversi:
-
ID bilangan bulat besar. ID resource cloud (ID akun AWS, nomor proyek GCP) dan nilai atribut yang dihitung bisa berupa angka besar. Konversi via Python atau Go untuk menghindari kehilangan presisi float64.
-
String batasan versi. Terraform menggunakan
~>,>=,<=dalam batasan versi provider. Ini adalah nilai string yang ditangani YAML dengan benar selama bukan kata Norway — tetapi~>aman. -
Nilai konfigurasi provider. Output plan Terraform dapat mencakup nilai konfigurasi untuk resource. Jika field boolean default ke
falsedan direpresentasikan sebagai"no"dalam skema provider tertentu, itu adalah risiko Norway dalam perjalanan kembali ke YAML. -
Blok
.sensitive_values. Nilai sensitif diredaksi sebagai booleantruedalam plan JSON. Ini selamat dari konversi dengan bersih karenatruebukan kata Norway di versi YAML mana pun.
Konversi Terraform-ke-YAML terutama untuk tinjauan manusia, bukan untuk dimasukkan kembali ke Terraform. Jangan gunakan manifest YAML sebagai input Terraform — format native Terraform adalah HCL, dan format input JSON-nya spesifik dan didokumentasikan secara terpisah.
Contoh Kode — 4 Bahasa
Node.js (eemeli/yaml + js-yaml)
Ekosistem Node.js memiliki dua library YAML dominan dengan penanganan Norway yang berbeda secara bermakna:
// eemeli/yaml — direkomendasikan, YAML 1.2 secara default, aman Norway
import { stringify } from 'yaml';
import { readFileSync } from 'fs';
const jsonInput = readFileSync('input.json', 'utf8');
const data = JSON.parse(jsonInput);
// Default: YAML 1.2 — "NO" tetap "NO", tidak ada konversi boolean
const yamlOutput = stringify(data);
console.log(yamlOutput);
// region: NO ← aman di 1.2, tetapi untuk kompatibilitas maksimum kutip secara eksplisit
// Paksa perilaku YAML 1.1 (untuk lingkungan K8s/Helm yang mem-parsing 1.1)
const yamlForK8s = stringify(data, { version: '1.1' });
// region: 'NO' ← dikutip otomatis karena 1.1 akan mem-parsing NO sebagai false
console.log(yamlForK8s);
// js-yaml — tersebar luas, tetapi semantik YAML 1.1, berisiko Norway tanpa kehati-hatian
import yaml from 'js-yaml';
import { readFileSync } from 'fs';
const data = JSON.parse(readFileSync('input.json', 'utf8'));
// Default dump — kata Norway mungkin tidak dikutip
const unsafe = yaml.dump(data);
// region: NO ← akan diparsing sebagai false jika dibaca kembali oleh parser 1.1!
// Lebih aman: gunakan skema kustom atau paksa pengutipan
const safer = yaml.dump(data, {
schema: yaml.JSON_SCHEMA, // membatasi ke tipe yang kompatibel JSON
noCompatMode: false,
lineWidth: -1,
quotingType: '"',
forceQuotes: false, // hanya mengutip saat diperlukan per skema JSON
});
Untuk proyek baru, lebih suka eemeli/yaml. Default YAML 1.2-nya lebih aman, Document API-nya memberikan kontrol halus atas pengutipan, dan ia menangani fidelitas round-trip dengan lebih baik. Untuk proyek yang sudah menggunakan js-yaml, gunakan opsi JSON_SCHEMA untuk membatasi ke tipe yang aman untuk JSON.
Python (PyYAML + ruamel.yaml)
Python adalah bahasa dominan untuk tooling Kubernetes, Ansible, dan pipeline rekayasa data — semuanya pengguna YAML berat.
import json
import yaml
import sys
# PyYAML — sederhana, standar, tetapi YAML 1.1 secara default
with open('input.json') as f:
data = json.load(f)
output = yaml.dump(data, default_flow_style=False, allow_unicode=True)
# country: 'NO' ← PyYAML cukup pintar untuk mengutip otomatis kata Norway
# Tetapi TIDAK mengutip "yes", "no" (huruf kecil) di semua konfigurasi:
# enabled: 'yes' ← dikutip
# tag: y ← mungkin atau tidak dikutip tergantung versi
print(output)
import json
import sys
from ruamel.yaml import YAML
# ruamel.yaml — fidelitas round-trip, mendukung YAML 1.2, direkomendasikan untuk produksi
yaml_rt = YAML()
yaml_rt.default_flow_style = False
yaml_rt.width = 4096 # mencegah pembungkusan baris yang tidak diinginkan
yaml_rt.best_map_flow_style = False
with open('input.json') as f:
data = json.load(f)
yaml_rt.dump(data, sys.stdout)
# Mempertahankan urutan kunci, menangani kata Norway dengan benar, mendukung anchor pada round-trip
Untuk skrip otomasi Ansible dan Kubernetes di mana Anda mengonversi respons JSON API ke manifest YAML, ruamel.yaml adalah pilihan yang lebih aman. PyYAML baik untuk skrip sederhana di mana Anda mengontrol data input dan telah memverifikasi tidak ada kata Norway yang muncul.
Go (gopkg.in/yaml.v3)
Go adalah bahasa ekosistem Kubernetes itu sendiri — kubectl, Helm, Argo, Flux, dan sebagian besar operator K8s ditulis dalam Go.
package main
import (
"encoding/json"
"fmt"
"os"
"gopkg.in/yaml.v3"
)
func main() {
// Baca input JSON
jsonBytes, err := os.ReadFile("input.json")
if err != nil {
panic(err)
}
// Unmarshal JSON ke dalam map generik
var data map[string]interface{}
if err := json.Unmarshal(jsonBytes, &data); err != nil {
panic(err)
}
// Marshal ke YAML — yaml.v3 menggunakan semantik YAML 1.2
yamlBytes, err := yaml.Marshal(data)
if err != nil {
panic(err)
}
fmt.Println(string(yamlBytes))
// country: "NO" ← yaml.v3 mengutip kata Norway dengan benar
// replicas: 3 ← bilangan bulat tetap bilangan bulat
// enabled: true ← boolean tetap boolean
}
yaml.v3 adalah peningkatan signifikan dibanding yaml.v2 untuk keamanan Norway. Library v2 mengikuti YAML 1.1 dan akan menulis NO tanpa kutipan; v3 mengutip nilai yang ambigu dengan benar. Jika Anda memelihara proyek Go lama yang menggunakan v2, upgrade ke v3 — API-nya sebagian besar kompatibel dan peningkatan keamanannya sepadan dengan migrasinya.
Untuk konversi type-safe dengan struct Go (daripada map[string]interface{}), gunakan tag struct:
type DeploymentLabels struct {
App string `yaml:"app" json:"app"`
Region string `yaml:"region" json:"region"`
}
// yaml.Marshal pada field struct yang berisi "NO" akan mengutipnya dengan benar di v3
Bash CLI (yq + jq)
Untuk shell script dan konversi one-off cepat, yq (versi Mike Farah, mikefarah/yq) mengonversi JSON ke YAML dalam satu perintah:
# Install 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
# Konversi file JSON ke YAML
yq -P < input.json > output.yaml
# Konversi dari output JSON kubectl
kubectl get deploy my-app -o json | yq -P > manifest.yaml
# Pipe melalui jq terlebih dahulu untuk filter/transform, kemudian konversi ke YAML
kubectl get deploy my-app -o json \
| jq 'del(.status, .metadata.creationTimestamp, .metadata.managedFields)' \
| yq -P > clean-manifest.yaml
Pipeline jq | yq adalah pola yang kuat: gunakan jq untuk manipulasi JSON (filter field, reshape struktur, query nilai) dan yq -P sebagai serializer YAML akhir. Untuk pola jq, lihat referensi jq command-line untuk 30 pola dunia nyata termasuk integrasi kubectl dan aws.
Peringatan Norway dengan yq: yq (mikefarah) menghormati tipe input dari JSON — string JSON "NO" dalam input akan diserialisasi sebagai string YAML dengan kutipan. Tetapi jika Anda menghasilkan YAML secara langsung dengan yq (bukan dari input JSON), Anda harus mengutip nilai kata Norway secara eksplisit. Gunakan konverter YAML ke JSON kami untuk memvalidasi round-trip setelah output yq.
Edge Case & Gotcha
Di luar masalah Norway, konversi JSON ↔ YAML memiliki beberapa edge case yang membingungkan engineer berpengalaman:
-
YAML multi-dokumen (pemisah
---). Satu file YAML dapat berisi beberapa dokumen yang dipisahkan oleh---. JSON tidak memiliki konsep yang setara. Saat mengonversi YAML multi-dokumen ke JSON, sebagian besar alat mengambil dokumen pertama saja, menggabungkan semua dokumen ke dalam array, atau error. Saat mengonversi JSON ke YAML, satu header dokumen---ditambahkan berdasarkan konvensi. Tentukan dan dokumentasikan perilaku Anda secara eksplisit untuk pipeline yang mungkin menghadapi file multi-dokumen. -
Anchor dan alias YAML. YAML mendukung definisi
&anchordan referensi*aliasuntuk konfigurasi DRY. Saat mengonversi YAML ke JSON, anchor harus diperluas — JSON yang dihasilkan mungkin jauh lebih besar dari YAML sumber. Saat mengonversi JSON ke YAML, konverter tidak dapat merekonstruksi anchor yang tidak ada dalam aslinya. Alias adalah fitur khusus YAML. -
Parsing implisit timestamp. Parser YAML 1.1 mengonversi
2024-05-04dan2024-05-04T12:00:00Zke objek tanggal native bahasa, bukan string. Ketika objek tanggal ini diserialisasi kembali ke JSON, outputnya tergantung pada library: beberapa menghasilkan string ISO, beberapa menghasilkan timestamp Unix, beberapa menghasilkan null. Round-tripping tanggal melalui YAML tanpa pengutipan string eksplisit ("2024-05-04") dapat diam-diam mengubah format. -
Tag
!!binary. YAML dapat menyematkan data biner yang dikodekan base64 dengan tag!!binary. JSON tidak memiliki tipe biner — biner harus berupa string base64. Saat mengonversi YAML dengan field!!binaryke JSON, dekode ke string base64. Saat mengonversi kembali, Anda tidak dapat merekonstruksi tag biner tanpa mengetahui skemanya. Kubernetes menggunakan!!binaryuntuk beberapa nilai secret. -
Tabrakan tipe kunci. JSON mengharuskan kunci objek berupa string. YAML mengizinkan kunci dari tipe apa pun — kunci bilangan bulat, kunci boolean, bahkan kunci objek kompleks. File YAML dengan
true: valueatau1: valuesebagai kunci tidak dapat direpresentasikan secara setia sebagai JSON. Sebagian besar konverter mengubah kunci menjadi string, tetapi semantiknya berubah. -
Varian representasi null. Dalam YAML,
null,~,Null,NULL, dan nilai kosong semuanya berarti null. Dalam JSON, hanyanullyang null. Saat mengonversi YAML ke JSON, semua ini dinormalisasi kenull. Tetapi saat mengonversi JSON kembali ke YAML, pilihan representasi null penting —~lebih ringkas,nulllebih eksplisit. Pilih satu dan tetap konsisten. -
Perubahan urutan kunci. Objek JSON secara teknis tidak memiliki urutan kunci yang ditentukan (meskipun sebagian besar parser mempertahankan urutan penyisipan). Pemetaan YAML juga tidak memiliki urutan yang diperlukan. Tetapi beberapa library YAML mengurutkan kunci secara alfabetis secara default saat serialisasi. Ini dapat menyebabkan diff besar dalam version control jika JSON sumber menggunakan urutan yang berbeda. Konfigurasikan
sort_keys=Falsedi PyYAML dan opsi yang setara di library lain.
Kapan TIDAK Mengonversi
Konversi tidak selalu merupakan jawaban yang tepat. Berikut skenario di mana tetap dalam format asli adalah pilihan yang lebih baik:
Jangan konversi YAML ke JSON jika YAML berisi komentar yang mendokumentasikan logika bisnis. Komentar YAML bukan bagian dari model data — komentar menghilang dalam serialisasi apa pun ke JSON. Jika manifest Kubernetes memiliki komentar yang menjelaskan mengapa batas resource tertentu dipilih atau mengapa pengecualian kebijakan keamanan dibuat, mengonversi ke JSON menghancurkan dokumentasi itu. Pertahankan YAML.
Jangan auto-konversi konfigurasi dalam pipeline CI tanpa uji round-trip. Jika pipeline Anda mengonversi JSON ke YAML dan kemudian menerapkan YAML ke cluster, tambahkan langkah validasi round-trip: YAML kembali ke JSON, kemudian bandingkan dengan yang asli. Ini menangkap kejutan konversi tipe sebelum mencapai produksi.
Jangan konversi hanya karena alat menghasilkan JSON. kubectl, aws, terraform, dan docker inspect semuanya menghasilkan JSON, tetapi sebagian besar alat ini juga menerima YAML sebagai input. Sebelum membangun langkah konversi, periksa apakah alat target dapat langsung menerima input YAML — sebagian besar alat DevOps modern dapat. Konverter YAML ke JSON kami paling berguna ketika Anda secara khusus membutuhkan JSON untuk alat yang tidak menerima YAML.
Jangan konversi jika skemanya berbeda. Jika JSON Anda menggunakan kunci camelCase dan konsumen YAML Anda mengharapkan snake_case (atau sebaliknya), Anda memerlukan langkah transform selain konversi format. Konversi format semata akan menghasilkan YAML yang benar secara sintaktis tetapi salah secara semantis. Tangani pemetaan skema secara eksplisit.
Jangan pertahankan kedua format secara manual. Jika Anda memelihara config.json dan config.yaml yang seharusnya setara, Anda akan mengalami drift. Pilih satu format kanonik dan turunkan yang lain secara otomatis — atau lebih baik, pilih satu format dan hilangkan duplikasi.
FAQ
Apakah masalah Norway YAML masih mempengaruhi sistem modern?
Ya — ini meresap di seluruh ekosistem. Kubernetes dan Helm menggunakan library yaml.v2 Go (semantik YAML 1.1) di bagian signifikan codebase mereka. Ansible menggunakan PyYAML (YAML 1.1). Workflow GitHub Actions diparsing oleh parser YAML internal GitHub yang memiliki perilakunya sendiri. Sebagian besar file YAML CI/CD di dunia nyata diproses oleh parser YAML 1.1. Asumsikan semantik 1.1 sampai Anda memverifikasi sebaliknya.
Mengapa saya mengonversi JSON ke YAML jika YAML lebih sulit diparsing?
Konversinya bukan tentang kesulitan parser — ini tentang keterbacaan yang dapat diedit manusia. JSON ideal untuk mesin; YAML ideal untuk manusia yang perlu membaca, mengedit, dan meninjau file konfigurasi. Manifest Kubernetes yang di-check-in ke git, ditinjau dalam pull request, dan disetel tangan oleh engineer harus berupa YAML. Manifest yang sama yang diambil dari API untuk pemrosesan terprogram harus berupa JSON. Konverter JSON ke YAML kami menjembatani keduanya.
Bisakah saya round-trip JSON ↔ YAML tanpa kehilangan?
Dengan pengecualian, ya — untuk data yang kompatibel dengan JSON. JSON adalah subset dari YAML 1.2, sehingga setiap dokumen JSON yang valid adalah YAML 1.2 yang valid. Pergi JSON → YAML → JSON seharusnya tanpa kehilangan untuk data apa pun tanpa konversi tipe implisit. Masalah Norway berarti string JSON "NO" dapat bertahan dalam pass maju hanya jika konverter mengutipnya, dan kemudian bertahan dalam pass balik hanya jika parser YAML menghormati kutipan. Gunakan library YAML 1.2 untuk kedua arah untuk menjamin round-trip tanpa kehilangan.
Apa library YAML paling aman untuk produksi?
Untuk Python: ruamel.yaml dikonfigurasi untuk YAML 1.2. Untuk Node.js: eemeli/yaml (paket yaml di npm). Untuk Go: gopkg.in/yaml.v3. Ketiganya mengimplementasikan semantik YAML 1.2 atau memiliki mode YAML 1.2 eksplisit dan menangani kata Norway dengan benar. Hindari library YAML 1.1 dalam proyek baru. Jika Anda harus menggunakan library 1.1 (PyYAML, js-yaml, yaml.v2) karena alasan kompatibilitas, selalu kutip string yang rentan terhadap Norway secara eksplisit.
Apakah manifest YAML Kubernetes mendukung komentar setelah konversi JSON?
Tidak — komentar tidak dapat dipulihkan dari JSON. JSON tidak memiliki sintaks komentar, jadi tidak ada yang perlu dikonversi. Ketika Anda menjalankan kubectl get deploy -o json dan mengonversi output ke YAML untuk penyimpanan git, YAML yang dihasilkan tidak akan memiliki komentar. Komentar dalam manifest Kubernetes harus ditulis oleh manusia setelah konversi. Inilah salah satu alasan mengapa mempertahankan YAML yang ditulis tangan sebagai sumber kanonik sering lebih disukai daripada round-tripping melalui JSON API.
Bagaimana cara menangani bilangan bulat besar seperti resourceVersion atau timestamp nanodetik?
Kubernetes metadata.resourceVersion adalah field string dengan sengaja — tim Kubernetes tahu bahwa parser JSON dalam JavaScript dan runtime berbasis float64 lainnya akan kehilangan presisi pada bilangan bulat besar. Selalu perlakukan sebagai string. Untuk bilangan bulat besar yang benar-benar numerik (seperti timestamp epoch nanodetik dalam beberapa sistem tracing), gunakan tipe int Python, int64 Go, atau BigInt Node.js untuk parsing. Jangan pernah melewatkannya melalui JSON.parse() dalam JavaScript tanpa fungsi reviver kustom. Saat mengonversi ke YAML, bilangan bulat besar ini aman — YAML tidak memiliki batas presisi untuk bilangan bulat. Bahayanya ada dalam round-trip kembali melalui parser JSON JavaScript.
Apakah YAML 1.2 sudah banyak diadopsi?
Tidak merata. Library bahasa utama telah bermigrasi: yaml.v3 Go, ruamel.yaml Python, dan eemeli/yaml Node.js semuanya mendukung atau default ke YAML 1.2. Tetapi Kubernetes, Ansible, dan sebagian besar ekosistem DevOps masih berjalan pada parser YAML 1.1 karena biaya kompatibilitas mundur dari migrasi. Adopsi YAML 1.2 dalam proyek baru direkomendasikan, tetapi asumsikan 1.1 untuk sistem mana pun yang tidak Anda konfigurasi sendiri.
Haruskah tim kami menstandarkan JSON atau YAML untuk konfigurasi?
Standarkan berdasarkan tujuan, bukan format. Gunakan JSON untuk konfigurasi yang dikonsumsi oleh kode (badan permintaan API, file konfigurasi SDK, tooling terprogram). Gunakan YAML untuk konfigurasi yang dikonsumsi oleh manusia (manifest Kubernetes, pipeline CI, konfigurasi deployment, playbook Ansible). Hindari mencampur keduanya untuk konfigurasi yang sama — pilih satu representasi per tipe konfigurasi dan otomatasikan konversinya jika Anda membutuhkan keduanya. Ketika Anda perlu mengonversi, baik JSON ke YAML maupun YAML ke JSON kami berjalan sepenuhnya di browser Anda — tidak ada data yang meninggalkan perangkat Anda.
Coba Sekarang
Siap mengonversi file nyata? Coba konverter JSON ke YAML kami untuk memurnikan JSON menjadi YAML Kubernetes yang aman — ia secara otomatis mengutip kata Norway (NO, yes, on, off, dan daftar boolean YAML 1.1 lengkap) dan memungkinkan Anda memilih indentasi 2 spasi atau 4 spasi. Untuk arah sebaliknya, konverter YAML ke JSON kami menangani anchor, alias, dan YAML multi-dokumen. Kedua alat berjalan sepenuhnya di browser Anda — data Anda tidak pernah meninggalkan perangkat, yang penting ketika Anda bekerja dengan manifest Kubernetes produksi atau Terraform plan yang berisi konfigurasi resource sensitif.