Pelajari cara membuat OpenAPI dari perilaku menggunakan Claude Code, lalu bandingkan dengan implementasi API Anda dan buat contoh validasi sederhana untuk klien dan server.

Kontrak OpenAPI adalah deskripsi bersama tentang API Anda: endpoint apa yang ada, apa yang Anda kirim, apa yang diterima kembali, dan seperti apa error. Ini adalah perjanjian antara server dan siapa pun yang memanggilnya (aplikasi web, aplikasi mobile, atau layanan lain).
Masalahnya adalah pergeseran. API yang berjalan berubah, tapi spec tidak. Atau spec “dirapikan” supaya terlihat lebih baik daripada kenyataan, sementara implementasi terus mengembalikan field aneh, melewatkan kode status, atau bentuk error yang tidak konsisten. Seiring waktu, orang berhenti mempercayai file OpenAPI, dan itu menjadi sekadar dokumen lain yang diabaikan.
Pergeseran biasanya muncul dari tekanan normal: perbaikan cepat dirilis tanpa memperbarui spec, field opsional baru ditambahkan "sementara", pagination berkembang, atau tim memperbarui “sumber kebenaran” yang berbeda (kode backend, koleksi Postman, dan file OpenAPI).
Menjaga kejujuran berarti spec cocok dengan perilaku nyata. Jika API kadang mengembalikan 409 untuk konflik, itu harus ada di kontrak. Jika field bisa null, sebutkan. Jika auth diperlukan, jangan biarkan kabur.
Alur kerja yang baik meninggalkan Anda dengan:
Poin terakhir penting karena kontrak hanya membantu ketika ditegakkan. Spec yang jujur ditambah pemeriksaan yang dapat diulang mengubah “dokumentasi API” menjadi sesuatu yang tim bisa andalkan.
Jika Anda mulai dengan membaca kode atau menyalin rute, OpenAPI Anda akan menggambarkan apa yang ada hari ini, termasuk kekhasan yang mungkin tidak ingin Anda janjikan. Sebaliknya, jelaskan apa yang seharusnya API lakukan untuk pemanggil, lalu gunakan spec untuk memverifikasi implementasi cocok.
Sebelum menulis YAML atau JSON, kumpulkan sekumpulan fakta kecil per endpoint:
Lalu tulis perilaku sebagai contoh. Contoh memaksa Anda menjadi spesifik dan membuatnya lebih mudah menyusun kontrak yang konsisten.
Untuk API Tasks, contoh happy path bisa: “Buat task dengan title dan dapatkan kembali id, title, status, dan createdAt.” Tambahkan kegagalan umum: “Missing title mengembalikan 400 dengan {\"error\":\"title is required\"}” dan “Tidak ada auth mengembalikan 401.” Jika Anda sudah tahu edge case, sertakan: apakah judul duplikat diizinkan, dan apa yang terjadi ketika ID task tidak ada.
Tangkap aturan sebagai kalimat sederhana yang tidak bergantung pada detail kode:
title wajib dan 1-120 karakter.”limit diatur (maks 200).”dueDate adalah date-time ISO 8601.”Terakhir, tentukan scope v1 Anda. Jika ragu, jaga v1 kecil dan jelas (create, read, list, update status). Simpan pencarian, bulk updates, dan filter kompleks untuk nanti agar kontrak tetap dapat dipercaya.
Sebelum Anda meminta Claude Code menulis spec, tulis catatan perilaku dalam format kecil yang dapat diulang. Tujuannya membuatnya sulit untuk “mengisi celah” dengan tebakan.
Template yang baik cukup pendek sehingga Anda benar-benar menggunakannya, tapi konsisten sehingga dua orang akan menggambarkan endpoint yang sama dengan cara yang mirip. Fokuskan pada apa yang API lakukan, bukan bagaimana diimplementasikan.
Gunakan satu blok per endpoint:
METHOD + PATH:
Purpose (1 sentence):
Auth:
Request:
- Query:
- Headers:
- Body example (JSON):
Responses:
- 200 OK example (JSON):
- 4xx example (status + JSON):
Edge cases:
Data types (human terms):
Tulis setidaknya satu request konkret dan dua respons. Sertakan kode status dan body JSON realistis dengan nama field aktual. Jika sebuah field opsional, tunjukkan satu contoh saat field itu hilang.
Sebutkan edge case secara eksplisit. Ini tempat di mana spec diam-diam menjadi tidak benar nanti karena setiap orang mengasumsikan hal berbeda: hasil kosong, ID tidak valid (400 vs 404), duplikat (409 vs perilaku idempoten), kegagalan validasi, dan batas pagination.
Juga catat tipe data dengan kata-kata biasa sebelum berpikir tentang skema: string vs number, format date-time, boolean, dan enum (daftar nilai yang diizinkan). Ini mencegah skema “cantik” yang tidak cocok dengan payload nyata.
Claude Code bekerja paling baik ketika Anda memperlakukannya seperti juru tulis yang teliti. Beri ia catatan perilaku dan aturan ketat untuk bagaimana OpenAPI harus dibentuk. Jika Anda hanya mengatakan “tulis spec OpenAPI,” biasanya Anda akan mendapatkan tebakan, penamaan yang tidak konsisten, dan kasus error yang hilang.
Tempelkan catatan perilaku Anda terlebih dahulu, lalu tambahkan blok instruksi ketat. Prompt praktis terlihat seperti ini:
You are generating an OpenAPI 3.1 YAML spec.
Source of truth: the behavior notes below. Do not invent endpoints or fields.
If anything is unclear, list it under ASSUMPTIONS and leave TODO markers in the spec.
Requirements:
- Include: info, servers (placeholder), tags, paths, components/schemas, components/securitySchemes.
- For each operation: operationId, tags, summary, description, parameters, requestBody (when needed), responses.
- Model errors consistently with a reusable Error schema and reference it in 4xx/5xx responses.
- Keep naming consistent: PascalCase schema names, lowerCamelCase fields, stable operationId pattern.
Behavior notes:
[PASTE YOUR NOTES HERE]
Output only the OpenAPI YAML, then a short ASSUMPTIONS list.
Setelah Anda mendapat draf, baca ASSUMPTIONS terlebih dahulu. Di situlah kejujuran dimenangkan atau hilang. Setujui apa yang benar, perbaiki yang salah, lalu jalankan ulang dengan catatan yang diperbarui.
Untuk menjaga penamaan konsisten, nyatakan konvensi di awal dan patuhi. Misalnya: pola operationId yang stabil, nama tag hanya kata benda, nama schema tunggal, satu Error bersama, dan satu nama skema auth yang dipakai di mana-mana.
Jika Anda bekerja di workspace vibe-coding seperti Koder.ai, akan membantu menyimpan YAML sebagai file nyata lebih awal dan beriterasi dalam diff kecil. Anda dapat melihat perubahan mana berasal dari keputusan perilaku yang disetujui versus detail yang ditebak model.
Sebelum Anda membandingkan apa pun dengan produksi, pastikan file OpenAPI konsisten secara internal. Ini tempat tercepat untuk menangkap pemikiran yang berharap dan kata-kata yang kabur.
Baca tiap endpoint seolah Anda pengembang klien. Fokus pada apa yang pemanggil harus kirim dan apa yang bisa mereka andalkan untuk diterima kembali.
Langkah tinjau praktis:
Respons error perlu perhatian ekstra. Pilih satu bentuk bersama dan gunakan ulang di mana-mana. Beberapa tim menjaga sangat sederhana ({ error: string }), yang lain memakai objek ({ error: { code, message, details } }). Keduanya bisa bekerja, tapi jangan mencampurnya di berbagai endpoint dan contoh. Jika Anda mencampurnya, kode klien akan menumpuk kasus khusus.
Skenario sanity cepat membantu. Jika POST /tasks mengharuskan title, skema harus menandainya required, respons kegagalan harus menunjukkan body error yang sebenarnya Anda kembalikan, dan operasi harus jelas menyatakan apakah auth diperlukan.
Setelah spec terbaca seperti perilaku yang dimaksud, anggap API yang berjalan sebagai kebenaran tentang apa yang klien alami hari ini. Tujuannya bukan “menang” antara spec dan kode. Tujuannya memunculkan perbedaan lebih awal dan membuat keputusan yang jelas pada tiap perbedaan.
Untuk pass pertama, sampel request/response nyata biasanya opsi paling sederhana. Logs dan tes otomatis juga bekerja jika dapat dipercaya.
Perhatikan mismatch umum: endpoint yang ada di satu tempat tapi tidak di tempat lain, perbedaan nama field atau bentuk, perbedaan kode status (200 vs 201, 400 vs 422), perilaku yang tidak didokumentasikan (pagination, sorting, filtering), dan perbedaan auth (spec mengatakan publik, kode memerlukan token).
Contoh: OpenAPI Anda menyatakan POST /tasks mengembalikan 201 dengan {id,title}. Anda memanggil API berjalan dan mendapatkan 200 plus {id,title,createdAt}. Itu bukan “cukup dekat” jika Anda menggenerasi SDK klien dari spec.
Sebelum mengedit apa pun, putuskan cara menyelesaikan konflik:
Jaga setiap perubahan kecil dan dapat ditinjau: satu endpoint, satu respons, satu tweak skema. Lebih mudah ditinjau dan lebih mudah dites ulang.
Setelah Anda punya spec yang dapat dipercaya, ubah menjadi contoh validasi kecil. Inilah yang mencegah drift kembali menyelinap.
Di server, validasi berarti gagal cepat ketika request tidak cocok kontrak, dan mengembalikan error yang jelas. Itu melindungi data Anda dan membuat bug lebih mudah ditemukan.
Cara sederhana mengekspresikan contoh validasi server adalah menulisnya sebagai kasus dengan tiga bagian: input, output yang diharapkan, dan error yang diharapkan (kode error atau pola pesan, bukan teks persis).
Contoh (kontrak mengatakan title wajib dan harus 1 sampai 120 karakter):
{
"name": "Create task without title returns 400",
"request": {"method": "POST", "path": "/tasks", "body": {"title": ""}},
"expect": {"status": 400, "body": {"error": {"code": "VALIDATION_ERROR"}}}
}
Di klien, validasi adalah tentang mendeteksi drift sebelum pengguna merasakannya. Jika server mulai mengembalikan bentuk berbeda, atau field wajib menghilang, tes Anda harus menandainya.
Fokus pemeriksaan klien pada apa yang benar-benar Anda andalkan, seperti “sebuah task punya id, title, status.” Hindari menegaskan setiap field optional atau urutan yang tepat. Anda ingin gagal pada perubahan yang merusak, bukan pada penambahan yang tidak berbahaya.
Beberapa pedoman supaya tes tetap mudah dibaca:
Jika Anda membangun dengan Koder.ai, Anda bisa menghasilkan dan menyimpan contoh kasus ini berdampingan dengan file OpenAPI, lalu memperbaruinya sebagai bagian dari review yang sama saat perilaku berubah.
Bayangkan API kecil dengan tiga endpoint: POST /tasks membuat tugas, GET /tasks men-list tugas, dan GET /tasks/{id} mengembalikan satu tugas.
Mulailah dengan menulis beberapa contoh konkret untuk satu endpoint, seolah menjelaskannya kepada tester.
Untuk POST /tasks, perilaku yang dimaksud bisa:
{ \"title\": \"Buy milk\" } dan dapatkan 201 dengan objek task baru, termasuk id, title, dan done:false.{} dan dapatkan 400 dengan error seperti { \"error\": \"title is required\" }.{ \"title\": \"x\" } (terlalu pendek) dan dapatkan 422 dengan { \"error\": \"title must be at least 3 characters\" }.Ketika Claude Code membuat draf OpenAPI, snippet untuk endpoint ini harus menangkap skema, kode status, dan contoh realistis:
paths:
/tasks:
post:
summary: Create a task
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskRequest'
examples:
ok:
value: { "title": "Buy milk" }
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
examples:
created:
value: { "id": "t_123", "title": "Buy milk", "done": false }
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
missingTitle:
value: { "error": "title is required" }
'422':
description: Unprocessable Entity
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
tooShort:
value: { "error": "title must be at least 3 characters" }
Satu mismatch umum bersifat halus: API berjalan mengembalikan 200 alih-alih 201, atau mengembalikan { "taskId": 123 } bukan { "id": "t_123" }. Itu jenis perbedaan “hampir sama” yang memecahkan klien yang digenerasi.
Perbaiki dengan memilih satu sumber kebenaran. Jika perilaku yang dimaksud benar, ubah implementasi supaya mengembalikan 201 dan bentuk Task yang disepakati. Jika perilaku produksi sudah diandalkan, perbarui spec (dan catatan perilaku) untuk mencerminkan kenyataan, lalu tambahkan validasi dan respons error yang hilang agar klien tidak terkejut.
Kontrak menjadi tidak jujur ketika ia berhenti mendeskripsikan aturan dan mulai mendeskripsikan apa pun yang API Anda kembalikan pada satu hari yang baik. Tes sederhana: apakah implementasi baru bisa lolos spec ini tanpa menyalin kekhasan hari ini?
Satu jebakan adalah overfitting. Anda menangkap satu respons dan mengubahnya menjadi hukum. Contoh: API Anda saat ini selalu mengembalikan dueDate: null, jadi spec mengatakan field selalu nullable. Padahal aturan nyata mungkin “diperlukan ketika status scheduled.” Kontrak harus mengekspresikan aturan, bukan sekadar dataset saat ini.
Error seringkali tempat kejujuran rusak. Godaan untuk menspesifikasi hanya respons sukses karena terlihat bersih. Tapi klien perlu dasar: 401 saat token hilang, 403 untuk akses terlarang, 404 untuk ID yang tidak dikenal, dan error validasi yang konsisten (400 atau 422).
Polanya lain yang menyebabkan masalah:
taskId di satu rute tapi id di tempat lain, atau priority sebagai string di satu respons dan number di respons lain).string, semuanya jadi optional).Kontrak yang baik bisa dites. Jika Anda tidak bisa menulis tes yang gagal dari spec, itu belum jujur.
Sebelum Anda menyerahkan file OpenAPI ke tim lain (atau menempelkannya ke docs), lakukan pemeriksaan cepat: "bisakah seseorang menggunakan ini tanpa membaca pikiran Anda?"
Mulai dari contoh. Spec bisa valid tapi tetap tidak berguna jika setiap request dan response terlalu abstrak. Untuk tiap operasi, sertakan setidaknya satu contoh request realistis dan satu contoh respons sukses. Untuk error, satu contoh per kegagalan umum (auth, validasi) biasanya cukup.
Lalu periksa konsistensi. Jika satu endpoint mengembalikan { "error": "..." } dan endpoint lain mengembalikan { "message": "..." }, klien harus menulis logika bercabang di mana-mana. Pilih satu bentuk error dan gunakan ulang, beserta kode status yang dapat diprediksi.
Daftar pemeriksaan singkat:
Trik praktis: pilih satu endpoint, pura-pura Anda belum pernah melihat API, dan jawab “Apa yang saya kirim, apa yang saya dapatkan kembali, dan apa yang bisa rusak?” Jika OpenAPI tidak bisa menjawab dengan jelas, itu belum siap.
Alur kerja ini berbuah ketika dijalankan secara rutin, bukan hanya saat rilis panik. Pilih aturan sederhana dan patuhi: jalankan setiap kali endpoint berubah, dan jalankan lagi sebelum Anda mempublikasikan spec yang diperbarui.
Sederhanakan kepemilikan. Orang yang mengubah endpoint memperbarui catatan perilaku dan draf spec. Orang kedua meninjau diff “spec vs implementasi” seperti review kode. Tim QA atau dukungan sering menjadi reviewer yang baik karena mereka cepat melihat respons yang tidak jelas dan edge case.
Perlakukan edit kontrak seperti edit kode. Jika Anda menggunakan builder berbasis chat seperti Koder.ai, ambil snapshot sebelum edit yang berisiko dan gunakan rollback bila perlu agar iterasi tetap aman. Koder.ai juga mendukung ekspor source code, yang memudahkan menyimpan spec dan implementasi berdampingan di repo.
Rutinitas yang biasanya bekerja tanpa memperlambat tim:
Aksi selanjutnya: pilih satu endpoint yang sudah ada. Tulis 5–10 baris catatan perilaku (input, output, kasus error), hasilkan draf OpenAPI dari catatan itu, validasi, lalu bandingkan dengan implementasi yang berjalan. Perbaiki satu mismatch, uji ulang, dan ulangi. Setelah satu endpoint, kebiasaan biasanya akan menempel.
OpenAPI drift adalah ketika API yang berjalan sebenarnya tidak lagi cocok dengan file OpenAPI yang dibagikan orang. Spec bisa kehilangan field baru, kode status, atau aturan otentikasi, atau bisa menggambarkan perilaku “ideal” yang server tidak ikuti.
Ini penting karena klien (aplikasi, layanan lain, SDK yang digenerasi, tes) membuat keputusan berdasarkan kontrak, bukan berdasarkan apa yang server Anda “biasanya” lakukan.
Pecahnya pengalaman klien jadi acak dan sulit di-debug: aplikasi mobile mengira akan mendapatkan 201 tapi malah dapat 200, SDK gagal mendeserialisasi karena field diganti nama, atau penanganan error rusak karena bentuk error berbeda.
Bahkan ketika tidak ada yang crash, tim kehilangan kepercayaan dan berhenti menggunakan spec—yang menghilangkan sistem peringatan dini Anda.
Karena kode mencerminkan perilaku saat ini, termasuk kekhasan yang mungkin tidak ingin Anda janjikan jangka panjang.
Cara yang lebih baik: tulis dulu perilaku yang dimaksud (input, output, error), lalu verifikasi implementasi cocok. Itu memberi Anda kontrak yang bisa ditegakkan, bukan sekadar snapshot rute hari ini.
Untuk tiap endpoint, tangkap:
Jika Anda bisa menulis permintaan konkret dan dua respons, biasanya sudah cukup untuk membuat draf spec yang jujur.
Pilih satu bentuk body error dan gunakan itu di mana-mana.
Contoh sederhana yang konsisten adalah salah satu dari:
{ "error": "message" }, atau{ "error": { "code": "...", "message": "...", "details": ... } }Lalu gunakan konsisten di semua endpoint dan contoh. Konsistensi lebih penting daripada kecanggihan karena klien akan mengandalkan bentuk ini.
Berikan Claude Code catatan perilaku Anda dan aturan ketat, lalu katakan untuk tidak mengada-ada. Set instruksi praktis seperti:
TODO di spec dan daftar di bawah ASSUMPTIONS.”Error) dan referensikan mereka.”Setelah generasi, tinjau bagian dulu. Di situlah kejujuran dimulai jika Anda menerima tebakan.
Validasi spec itu sendiri dulu:
201)Ini mencegah file OpenAPI yang “berharap” sebelum Anda melihat perilaku produksi.
Anggap API yang berjalan sebagai apa yang pengguna alami hari ini, lalu putuskan per ketidaksesuaian:
Jaga perubahan kecil (satu endpoint atau satu respons saja) agar mudah dites ulang.
Validasi server berarti menolak cepat ketika request tidak cocok kontrak, dan mengembalikan error yang jelas. Itu melindungi data dan mempermudah menemukan bug.
Validasi klien berarti mendeteksi drift sebelum pengguna merasakannya dengan memeriksa hanya apa yang benar-benar Anda andalkan:
Jangan mengetes setiap field optional agar tes hanya gagal pada perubahan yang merusak, bukan penambahan aman.
Rutinitas praktis:
Jika Anda memakai Koder.ai, simpan file OpenAPI bersama kode, ambil snapshot sebelum perubahan berisiko, dan rollback jika perubahan spec/kode berantakan.