JSON Toolkit

Validasi JSON di CI: Pipeline dengan jsonlint, ajv, dan jq

Intinya: Validasi sintaks membuktikan file dapat di-parse; validasi schema membuktikan field mengikuti kontrak. Di CI, yang penting adalah exit code yang tidak ambigu, lokasi error, dan jalur perbaikan.

Menengah±10 menit bacaDiterbitkan 2026-10-31Diperbarui 2026-10-31
Sampul artikel validasi JSON di CI

Intinya: di CI, biarkan jq empty menangani sintaks, ajv-cli menangani struktur (check-jsonschema untuk tim multi-format), dan Prettier menangani gaya; rangkai berdasarkan lapisan dan berhenti pada kegagalan pertama.

Lolos parser di editor lokal Anda tidak berarti file itu layak masuk CI; lolos CI juga tidak berarti field-nya sesuai kontrak.

1. Pisahkan validasi sintaks dari validasi schema

Frasa "validasi JSON" digunakan terlalu luas, itulah sebabnya tim sering memilih satu alat untuk memecahkan dua masalah berbeda:

Lapisan Pertanyaan yang dijawab Alat tipikal Arti kegagalan
Sintaks Apakah file ini JSON yang valid? jq empty, jsonlint, python -m json.tool Kurung, koma, tanda kutip, atau encoding rusak
Schema Apakah field, tipe, dan properti wajib sesuai kontrak? ajv-cli, check-jsonschema File dapat di-parse, tetapi struktur bisnisnya salah
Gaya Apakah indentasi dan urutan kunci konsisten? Prettier, jq -S Format tidak konsisten dan diff berisik

Lapisan-lapisan ini tidak dapat saling menggantikan. File yang lolos sintaks masih bisa gagal schema: {"price": "12.5"} adalah JSON yang valid, tetapi jika schema mengharuskan price berupa angka, maka ia tidak dapat diterima. Sebaliknya, betapapun lengkap schema-nya, file yang kehilangan kurung tutup tidak akan pernah dapat dikompilasi terhadapnya.

Jadi pipeline harus menjalankan sintaks dulu, struktur kedua, dan gaya terakhir. Berhenti segera setelah satu lapisan gagal, jika tidak error parse akan menyamar sebagai error field.

2. Lapisan sintaks: jq empty adalah opsi dengan dependensi minimal

Jika jq sudah ada di image CI, validasi sintaks hampir tidak memakan biaya:

jq empty data.json

jq empty tidak menghasilkan output; ia hanya mem-parse file. Ia keluar dengan 0 saat berhasil dan kode non-nol plus informasi baris/kolom saat gagal. Itu membuatnya lebih ringan daripada menarik seluruh pohon dependensi Node, dan menjadi gerbang pertama yang baik.

Saat memvalidasi file JSON secara batch di repositori, kecualikan node_modules, output build, dan cache pihak ketiga:

find . -name '*.json' \
  -not -path './node_modules/*' \
  -not -path './dist/*' \
  -print0 | xargs -0 -n1 jq empty

-print0 dan xargs -0 menangani spasi pada nama file, sementara -n1 memastikan satu file per pemanggilan agar pesan error mengidentifikasi biang keladinya. Jangan teruskan ratusan file ke satu proses; pesan error akan saling menimpa.

jsonlint adalah pilihan umum lainnya, biasanya dipanggil sebagai npx jsonlint -q data.json, di mana -q hanya mencetak error. Ia melaporkan nomor baris dan kolom, tetapi pemeliharaannya kurang aktif dibanding jq, dan versi berbeda menoleransi BOM serta komentar secara berbeda. Perlakukan ia sebagai pemeriksa sintaks yang lebih mudah dibaca, bukan sebagai validator schema.

3. Lapisan schema: dasar-dasar ajv-cli validate

Ajv adalah validator schema yang paling banyak digunakan di ekosistem JavaScript, dan ajv-cli mengeksposnya sebagai alat command-line:

ajv validate -s schema.json -d data.json

-s menunjuk ke file schema dan -d ke data yang divalidasi. Saat gagal, proses keluar dengan kode non-nol, sehingga CI langsung gagal. Proyek nyata biasanya menambahkan dua flag:

npx ajv-cli validate \
  -s schemas/order.json \
  -d 'fixtures/orders/*.json' \
  --strict=false \
  --errors=text

--strict=false membantu untuk schema lama: mode ketat memperlakukan kata kunci tak dikenal dan deklarasi required yang mencurigakan sebagai error, yang sering gagal pada banyak schema warisan. --errors=text menghasilkan output yang dapat dibaca manusia, sementara struktur JSON bawaan lebih baik untuk mesin. Pilih berdasarkan siapa yang mengonsumsi hasilnya.

Versi draft schema juga harus cocok. Versi mayor Ajv mendukung draft berbeda secara bawaan, dan ajv-cli dapat memilih salah satunya dengan --spec=draft7, --spec=draft2019, atau --spec=draft2020. Jika sebuah schema menyatakan $schema: "https://json-schema.org/draft/2020-12/schema" tetapi CLI mengompilasinya sebagai draft-07, sebagian kata kunci akan diabaikan secara diam-diam. Untuk lebih lanjut tentang penulisan schema dan perbedaan versi, lihat Memulai JSON Schema.

Validasi format adalah kebutuhan lain yang sering muncul. Kata kunci format hanya bersifat anotasi secara bawaan; agar email, date-time, dan uri benar-benar menegakkan sesuatu, muat ajv-formats:

npx ajv-cli validate -c ajv-formats -s schema.json -d data.json

Langkah ini mudah terlewat, dan akibatnya field email menerima not-an-email. Sebelum merilis, beri pipeline satu record yang sengaja tidak valid; itu membuktikan aturannya aktif jauh lebih baik daripada membaca dokumentasi sepuluh kali.

check-jsonschema: banyak format dan error yang lebih ramah

Jika tim menangani YAML, TOML, atau konfigurasi GitHub Actions selain JSON, check-jsonschema lebih nyaman:

check-jsonschema --schemafile schemas/config.json config/app.json
check-jsonschema --schemafile schemas/pipeline.json .github/workflows/ci.yml

Keunggulan praktisnya:

  1. Dukungan YAML native, yang cocok untuk file yang "berbentuk JSON tetapi ditulis dalam YAML", seperti manifest Kubernetes dan konfigurasi CI.
  2. Error mencakup path file, nomor baris, dan path field, sehingga biaya pelokasian rendah.
  3. Hook pre-commit disediakan, sehingga integrasinya murah.
  4. Ia dapat mengambil schema umum dari SchemaStore, tetapi juga menerima file lokal, menghindari dependensi jaringan.

Dalam tim lintas bahasa, Python sering sudah tersedia, sehingga memasang dan meningkatkan check-jsonschema lebih ringan daripada memelihara toolchain Node. Biarkan jq menangani sintaks dan alat ini menangani struktur; kombinasi ini memiliki biaya pemeliharaan yang sangat rendah.

4. Exit code adalah satu-satunya sinyal CI yang dapat dipercaya

Betapapun rapi outputnya, CI hanya membaca exit code. Tiga jebakan yang umum:

Gejala Penyebab Perbaikan
Ada error tetapi CI hijau Perintah diakhiri dengan `
Tidak ada error tetapi CI merah diff memperlakukan "ditemukan perbedaan" sebagai kegagalan Bedakan "perbedaan" dari "error eksekusi"
Output error terpotong Output multi-file paralel saling menimpa Jalankan berurutan atau cetak per file

Ingat semantik exit code jq: parsing normal mengembalikan 0; dengan -e, hasil ekspresi false atau null mengembalikan 1; error penggunaan dan file hilang mengembalikan 2; error kompilasi skrip mengembalikan 3. Alat schema umumnya menggunakan 0 untuk sukses, 1 untuk kegagalan validasi, dan 2 untuk error alat atau argumen. Saat menulis wrapper, jangan menyatukan setiap kode non-nol menjadi "datanya salah", atau kegagalan lingkungan akan salah didiagnosis sebagai masalah konten.

5. pre-commit: tangkap masalah sebelum commit

Nilai pre-commit bukan "satu pemeriksaan lagi"; melainkan memberi pengembang umpan balik dalam satu menit alih-alih setelah jalur CI sepuluh menit. Konfigurasi minimalnya terlihat seperti ini:

repos:
  - repo: https://github.com/python-jsonschema/check-jsonschema
    rev: 0.33.0
    hooks:
      - id: check-jsonschema
        files: ^configs/.*\.json$
        args:
          - --schemafile
          - schemas/config.json
  - repo: local
    hooks:
      - id: jq-syntax
        name: jq syntax check
        entry: jq empty
        language: system
        files: ^configs/.*\.json$

Dua detail penting:

  • files harus hanya cocok dengan direktori yang perlu divalidasi. Jangan menjalankan hook terhadap node_modules atau file yang dihasilkan.
  • Hook lokal mengasumsikan jq terpasang di mesin pengembang. Dokumentasikan persyaratan itu, atau beralih ke hook dalam container.

Jika proyek sudah menggunakan Husky dan lint-staged, gabungkan langsung:

{
  "lint-staged": {
    "configs/*.json": ["jq empty", "prettier --check"]
  }
}

Ingat bahwa lint-staged meneruskan daftar file yang di-stage, sehingga perintahnya harus menerima banyak path. Baik jq empty maupun prettier --check menerimanya. Jangan biarkan hook memindai seluruh repositori; commit akan menjadi jauh lebih lambat.

6. GitHub Actions: pipeline yang dapat Anda salin

Workflow di bawah menjalankan validasi sintaks, validasi schema, dan mempertahankan laporan saat gagal:

name: json-validate

on:
  push:
    paths:
      - 'schemas/**'
      - 'fixtures/**'
  pull_request:

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Syntax check
        run: |
          find fixtures -name '*.json' -print0 | xargs -0 -n1 jq empty
      - name: Schema check
        run: |
          npx --yes ajv-cli validate \
            -s schemas/order.json \
            -d 'fixtures/orders/*.json' \
            --strict=false \
            --errors=text

Filter paths mencegah perubahan yang hanya dokumentasi memicu validasi. npx --yes cocok untuk repositori tanpa dependensi yang dipatok; proyek produksi sebaiknya menambahkan ajv-cli ke devDependencies dan mematok versinya. Tanpa lock, rilis upstream yang mengubah draft bawaan atau mode ketat dapat membuat pipeline merah dalam semalam.

7. Pelokasian error: dari nomor baris ke path field

Separuh nilai validator adalah deteksi; separuh lainnya adalah pelokasian. Pelajari cara membaca tiga jenis output:

  1. Error sintaks: jq melaporkan baris dan kolom, sering dengan cuplikan di dekatnya. Perbaiki kurung dan koma terlebih dahulu; jangan langsung mencurigai encoding.
  2. Error schema: instancePath Ajv menunjuk ke lokasi data (misalnya /items/0/price), schemaPath menunjuk ke aturan (misalnya #/properties/items/items/properties/price/type), dan keyword menamai batasan yang dilanggar.
  3. Error format: ketika pemeriksaan format gagal, pesannya sering hanya mengatakan "must match format "email"". Gabungkan dengan instancePath untuk mengidentifikasi field-nya.

Tempelkan instancePath ke catatan penyelidikan; itu jauh lebih berguna daripada dinding JSON. Untuk array, indeks numerik juga memberi tahu Anda record mana yang gagal. Jika kunci bisnis lebih intuitif, tambahkan baris pemetaan setelahnya, seperti items[0].id = ORD-042.

Kesalahan schema yang umum, seperti penggunaan additionalProperties: false secara berlebihan atau menulis cabang oneOf yang sebenarnya saling tumpang tindih, dibahas di Jebakan umum pembuatan JSON Schema. Aturan validasi yang salah lebih berbahaya daripada tidak ada validasi, karena menciptakan rasa aman yang palsu.

8. Tabel pemilihan alat

Kebutuhan Alat yang disarankan Alasan Yang perlu diwaspadai
Hanya sintaks jq empty Nol dependensi, cepat, exit code jelas Spasi pada nama file saat menjalankan batch
Error baris/kolom lebih ramah jsonlint Output mudah dibaca Aktivitas pemeliharaan terbatas
Validasi JSON Schema ajv-cli Ekosistem matang, error terstruktur Selaraskan versi draft dan muat dukungan format
Repositori campuran JSON dan YAML check-jsonschema Multi-format, ramah pre-commit Sumber schema dan akses jaringan
Umpan balik cepat sebelum commit pre-commit / lint-staged Hanya memproses file yang di-stage Hook harus menerima banyak path
Format yang konsisten Prettier Diadopsi luas Gunakan --check bila tidak ingin menulis ulang file

Satu rekomendasi terakhir: pastikan pipeline benar-benar gagal dengan memberinya satu record yang sengaja tidak valid terlebih dahulu. Risiko terbesar bukanlah konfigurasi yang rumit; melainkan konfigurasi yang tidak pernah berlaku. Memperlakukan "ia dapat gagal" sebagai kriteria penerimaan lebih andal daripada memperlakukan "ia lolos" sebagai kriteria. Untuk toolchain command-line yang lebih luas, lanjutkan ke Editor, command line, dan otomasi.

FAQ

Haruskah saya menggunakan jq empty atau jsonlint?

Utamakan jq empty di CI: nol dependensi, startup cepat, dan semantik exit code yang jelas. Gunakan jsonlint ketika Anda membutuhkan pesan baris/kolom yang lebih ramah atau sedang menyelidiki secara lokal. Keduanya hanya melakukan validasi sintaks; tidak ada yang memeriksa struktur field.

Mengapa ajv melaporkan kata kunci tak dikenal?

Pertama pastikan draft $schema pada schema cocok dengan versi yang digunakan CLI. Banyak error "kata kunci tak dikenal" sebenarnya adalah kata kunci draft baru yang ditemui kompilator lama. Jika versinya cocok, periksa kesalahan ketik. --strict=false dapat menjaga schema warisan tetap berjalan, tetapi jangan mengandalkannya dalam jangka panjang untuk menyembunyikan masalah nyata.

Validasi schema lolos, tetapi API masih gagal. Mengapa?

Schema memvalidasi struktur, bukan semantik bisnis. Misalnya, status mungkin string dengan enum yang sah, sementara state machine melarang perpindahan langsung dari paid ke refunded. Aturan seperti itu berada di kode atau batasan basis data, bukan di JSON Schema.

Bagaimana cara menemukan field yang gagal dengan cepat?

Baca instancePath atau nomor baris dari output alat. instancePath Ajv adalah JSON Pointer yang menunjuk langsung ke data; check-jsonschema melaporkan file dan baris. Catat path dan petakan ke kunci bisnis; melokasikan masalah biasanya memakan beberapa menit.

Haruskah pre-commit menjalankan validasi penuh?

Tidak. pre-commit sebaiknya memproses hanya file yang di-stage agar commit tetap cepat. Pemindaian penuh milik CI atau job terjadwal. Pembagiannya sederhana: eksekusi lokal mengutamakan kecepatan, CI mengutamakan kelengkapan.