Skip to content

Koma yang Memotong Deskripsi: Parsing YAML di Balik Lint OpenAPI

Adityo Guni Waluyo

Delapan dari sepuluh error lint OpenAPI bukan soal kontrak: koma tak berkurung di dalam flow mapping memotong deskripsi jadi entri null.

Ringkasan

Error linting OpenAPI itu ternyata bukan contract drift, cuma koma di deskripsi YAML yang gak dikasih tanda kutip. Parser motong nilai di koma pertama, jadi deskripsi kepotong tanpa warning. Solusinya gampang, quote semua deskripsi, terus regenerate tipe buat mastiin hasilnya identik byte-per-byte.

Saya lagi jalanin linting buat spesifikasi OpenAPI proyek KotaPortal, dan terminal langsung meledak: 10 error struktur. Insting pertama saya, contract drift. Ada yang nambahin field di handler tanpa update spek, atau seseorang ubah skema respons diam-diam. Saya buka riwayat commit buat cari perubahan definisi respons atau parameter yang mencurigakan.

Tidak ada. File yang disentuh cuma api/docs/openapi.yaml, dan perubahan terakhir bersifat higienis, bukan kontraktual. Penelusuran lebih dalam membawa saya ke lapisan yang lebih dasar: masalahnya bukan di OpenAPI-nya, tapi di parser YAML-nya.

Komanya Bukan Teks

Dari 10 error itu, 8 berasal dari deskripsi di dalam flow-mapping yang mengandung koma tanpa tanda kutip. Di dalam kurung kurawal, koma bukan karakter teks biasa. Spesifikasi YAML 1.2.2 menyebut kurung siku, kurung kurawal, dan koma sebagai penanda yang "menandai struktur di dalam flow collection" dan karenanya dilarang di kasus tertentu untuk menghindari ambiguitas [1]. Konsekuensinya, plain scalar di dalam flow collection wajib dibersihkan dari karakter penanda tersebut [1].

Jadi ketika ada deskripsi seperti description: digits, max 2 MB di dalam sebuah mapping, parser memotong di koma pertama: nilai jadi digits, lalu max 2 MB berubah jadi entri mapping baru dengan kunci null. Fragmen-fragnya tetap hidup sebagai potongan mengambang yang diparsing tanpa error. Parser YAML-nya sendiri senang-senang saja, karena menurut gramatika memang tidak ada yang salah. Yang rusak adalah data yang sampai ke lapisan berikutnya, dan kehilangan itu senyap: tidak ada warning, tidak ada baris gagal, cuma kalimat yang tiba-tiba terpotong di tengah.

Linting Membaca Puing, Bukan Teks Asli

Di sinilah asumsi pertama saya meleset. Redocly CLI memang alat "untuk bekerja dengan deskripsi OpenAPI ... termasuk linting, enhancement, dan bundling" [2], tapi linting bekerja di atas data yang sudah diparsing. Kalau di config Redocly sebuah rule diset severity: error, "deskripsi API tidak lolos validasi" [3] ketika rule-nya kena. Yang dinilai adalah hasil parsing yang sudah terpotong itu. Error struct-nya muncul, tapi penyebabnya sudah terjadi beberapa lapis di bawah, jauh sebelum Redocly sempat melihat satu baris pun dari file-nya.

Ini juga menjelaskan kenapa jumlah errornya tidak cocok dengan jumlah kesalahan manusia. Sepuluh error, delapan di antaranya berasal dari satu penyebab yang sama berulang di field deskripsi, dan dua sisanya di lokasi berbeda. Kalau saya berhenti di angka 10 dan mulai memperbaiki satu per satu tanpa mencari pola, saya akan mengedit teks yang memang sudah benar secara semantik dan tetap kena.

Praktisnya: quote setiap kalimat manusia di dalam deskripsi. Tanda kutip ganda mengembalikan nilai persis seperti yang sudah diparse mesin, jadi ini koreksi sintaksis, bukan perubahan logika. Deskripsi berisi koma di dalam flow mapping tanpa kutipan itu tetap legal buat parser; yang tidak ada jaminannya adalah hasilnya utuh.

Bukti: Regenerasi Identik Byte

Cara saya memastikan perbaikan ini murni higienis: jalankan ulang openapi-typescript, yang mengubah skema OpenAPI 3.0/3.1 menjadi tipe TypeScript "runtime-free" [4]. File v1.d.ts keluar identik byte-per-byte, dan git status bersih. Tidak ada kontrak yang berubah. Nilai yang dipulihkan kutipan memang nilai yang selama ini sudah diparse; cuma teks mentahnya sekarang kebal terhadap ambiguitas parser.

Bukti regenerasi ini penting karena dia menjawab keberatan paling wajar: bagaimana kalau kutipan justru mengubah isi deskripsi? Kalau iya, tipe hasil generate pasti beda. Kenyataannya nol baris berubah, dan itu sekaligus menandai batas antara dua jenis perbaikan yang sering tercampur dalam satu commit.

Sisa 17 warning soal cakupan respons 2xx/4xx sengaja tidak disentuh. Mendokumentasikan respons 401 menambah entry di tipe hasil generate: satu 401 terbukti menambah 7 baris di v1.d.ts. Itu perubahan kontrak, di luar ruang lingkup pass higienis. Memperbaiki semuanya sekaligus di satu commit justru menghapus bukti bahwa perbaikan utamanya tidak mengubah apa pun.

Pelajaran yang saya bawa keluar dari investigasi ini: linter adalah pemeriksa, bukan tukang perbaikan. Kalau teks deskripsi tidak bertahan utuh melewati parser, tidak ada validator yang bisa menyelamatkan, dan dugaan pertama hampir selalu menyalahkan kontrak padahal yang rusak baru sintaksis.

Sources

Artikel terkait