Biasanya kelihatan saat pipeline API mulai menyesatkan tim. Schema berubah, generated types ikut ter-update tanpa error, PR hijau, tapi seseorang di frontend tetap membaca response shape lama karena wrapper-nya membuang error. Itulah masalah OpenAPI TypeScript, bukan soal apakah generator bisa menghasilkan interface.
Pertanyaan yang berguna justru lebih sulit. Kontrak seperti apa yang Anda inginkan antara schema, transport, dan validasi, dan bagian mana yang harus fail fast di build time alih-alih bocor ke runtime? Begitu Anda membingkai OpenAPI TypeScript sebagai pilihan pipeline, trade-off menjadi jauh lebih jelas, dan alat-alat tersebut tidak lagi berpura-pura menjadi solusi lengkap.
Table of Contents
- Mengapa Generated Types Tidak Sama dengan API yang Aman
- Generate TypeScript Types dari Spec OpenAPI
- Pilih Pure Types, Full Clients, atau Tanpa Codegen
- Membuat Thin Typed Client dengan Fetch atau Axios
- Tambah Runtime Validation dengan zod, ajv, atau io-ts
- Integrasikan Generation, Validation, dan Contract Tests ke CI
- Pipeline yang Maintainable, Performa, dan Checklist Akhir
Mengapa Generated Types Tidak Sama dengan API yang Aman
Seorang rekan melakukan merge PR yang menambahkan field response opsional. File yang di-generate terupdate dengan lancar, diff-nya terlihat biasa saja, dan semua orang lanjut bekerja. Namun, front end terus membaca bentuk data lama melalui wrapper manual yang di-cast secara "sementara" dengan as any, dan produksi mulai berperilaku seolah-olah kontraknya tidak pernah berubah.
Itulah jebakan dari tipe data yang di-generate. TypeScript hanya bisa melindungi code yang mengonsumsi tipe data hasil generate tersebut, dan itu pun jika transport layer tidak menghapus kontraknya lagi. Sisi OpenAPI memberi Anda skema, bukan jaminan bahwa setiap pemanggil mematuhinya. Diskusi diskusi seputar pemahaman koneksi API sangat berguna di sini karena mengalihkan fokus dari sekadar satu tool ke arah bagaimana sistem saling terhubung.
Di mana letak kegagalannya
Breakpoint yang paling umum itu membosankan, bukan sesuatu yang eksotis. Pergeseran skema terjadi saat spec OpenAPI dan service yang dideploy tidak lagi sinkron. Cakupan parsial muncul saat spec hanya memodelkan happy path, padahal app bergantung pada edge case yang tidak terdokumentasi. Wrapper buatan manual sering kali jadi tempat tipe data melemah, terutama saat seseorang ingin “move fast” dan memakai any atau cast response yang longgar.
Aturan praktis: jika wrapper-nya bisa berbohong, generator tidak bisa menyelamatkanmu.
Ada juga celah runtime. Tipe TypeScript hilang setelah kompilasi, jadi tidak bisa menolak JSON malformed yang datang lewat jaringan. Network tidak peduli dengan inferensi editor Anda, itulah sebabnya client hasil generate hanyalah satu lapisan dalam pipeline API yang lebih aman.
Pertanyaan operasional yang lebih luas adalah keamanan dan disiplin kontrak, bukan sekadar kenyamanan developer. Jika Anda ingin melihat struktur bagaimana kontrak API masuk ke dalam lifecycle app yang lebih besar, panduan internal tentang standar keamanan API untuk kepatuhan app store adalah pendamping yang berguna.
Cara berpikir matang tentang openapi typescript adalah seperti ini. Ini memberi Anda jembatan schema-to-types yang ketat, yang memang sangat bagus, tetapi tidak memvalidasi request, tidak menegakkan bentuk payload saat runtime, dan tidak mencegah wrapper yang ceroboh merusak semuanya. Generator hanyalah 20 persen yang mudah. Sisanya adalah desain pipeline, dan di situlah tim entah membangun kepercayaan atau justru menumpuk kepercayaan diri yang semu.
Generate TypeScript Types dari Spec OpenAPI

Setup paling ringan yang berguna biasanya adalah yang mampu bertahan menghadapi perubahan repo di dunia nyata. Simpan spec OpenAPI di repositori yang sama, generate file type yang di-commit, dan buat drift terlihat di CI daripada mengandalkan seseorang untuk mengingat langkah refresh. Perintah seperti npx openapi-typescript ./openapi.yaml -o ./src/types/api.d.ts memberikan Anda file output deterministik yang bisa diperiksa reviewer layaknya perubahan source code lainnya.
Flag yang benar-benar penting
Panduan -o Flag output itu penting karena membuat artefak yang di-generate menjadi eksplisit. --immutable berguna saat Anda ingin tipe yang di-generate tetap mempertahankan intent readonly pada output, dan --alphabetize menjaga diff tetap stabil saat urutan schema berubah tanpa mengubah makna semantiknya. --enum menjadi penting saat tim Anda lebih menyukai enum pada hasil generate daripada union.
Dokumentasi proyek ini sudah jelas mengenai cakupannya, yaitu sebuah generator tipe, bukan client runtime atau request layer, dan batasan tersebut sangat membantu jika Anda menginginkan setup yang ringan dan type-first. Repositorinya juga menunjukkan model pemeliharaan tool ini, yang menjadi alasan mengapa tooling open source bisa andal di produksi selama dokumentasi dan rilisnya tetap aktif, seperti yang dibahas dalam argumen untuk pemeliharaan open source. Bacaan praktis mengenai hal tersebut ada di repositori GitHub dan dokumentasi CLI.
Generate wire ke dalam package.json agar command tersebut berada di samping build scripts lainnya, lalu jalankan setiap kali spec berubah. Di CI, regenerasi file dan gagalkan proses jika git diff menunjukkan adanya drift. Ini mengubah perubahan contract menjadi pekerjaan review yang terlihat, bukan risiko runtime yang tersembunyi.
Sisi skema sama pentingnya dengan command line. Proyek ini merekomendasikan compilerOptions.noUncheckedIndexedAccess agar additionalProperties menjadi T | undefined, yang memaksa indexing lebih aman saat pemanggilan. Ini juga menyarankan penggunaan oneOf secara mandiri daripada mencampurnya dengan komposisi tambahan, dan menjaga $defs di root jika penempatannya ambigu, karena definisi yang salah tempat bisa hilang dari output yang dihasilkan. Satu detail lagi untuk menghemat waktu, openapi-typescript tidak akan pernah menghasilkan any, sehingga detail schema yang kurang akan terdeteksi lebih awal daripada tersembunyi di balik tipe yang terlalu permisif.
Pastikan spec tetap eksplisit, jika tidak, generator akan menampilkan ambiguitas tersebut kembali kepada Anda.
Workflow yang berkelanjutan sangatlah sederhana. Simpan spec di version control, regenerasi saat build, commit file yang dihasilkan, dan biarkan type checker memberi peringatan sebelum ada yang melakukan merge pada ketidakcocokan. Ini memberi Anda batasan contract yang stabil untuk sisa pipeline Anda.
Pilih Pure Types, Full Clients, atau Tanpa Codegen
| Pola | Waktu build | File output | Ukuran bundle | Pilihan terbaik |
|---|---|---|---|---|
| Pure types dengan wrapper tipis | Cepat | Sedikit | Rendah | Tim yang ingin kontrol dan runtime minimal |
| Codegen full-client | Lebih lambat | Banyak | Lebih tinggi | Tim yang ingin handoff cepat dan operasi otomatis |
| Tidak ada builder request codegen | Cepat | Tidak ada atau minimal | Rendah | Aplikasi single-codebase yang lebih suka menulis logika transport secara manual |
Pilihannya bukan soal "tool mana yang menang". Tapi pipeline mana yang paling cocok dengan repo, tim, dan seberapa sering API mengalami perubahan. Dalam benchmark 2025 pada spec OpenAPI besar sekitar 75.000 baris, 2 MB, dan sekitar 1.200 operasi, openapi-typescript output yang dihasilkan dalam waktu sekitar 1,5 detik secara rata-rata, dibandingkan dengan sekitar 8,0 detik untuk @hey-api/openapi-ts, 5,5 detik untuk Orval, dan 18,1 detik untuk Kubb, sekaligus menghasilkan satu file output dibandingkan 16 untuk hey-api, 2,719 untuk Orval, dan 3,877 untuk Kubb (detail benchmark).
Pure types lebih mengutamakan kontrol
Setup pure-types sangat cocok dipasangkan dengan request layer buatan sendiri karena Anda bisa menjaga runtime tetap kecil dan API tetap simpel. Hal ini penting pada frontend yang sensitif terhadap bundler dan pada aplikasi di mana satu tim mengelola spec sekaligus consumer-nya. Jika Anda butuh pengingat bahwa developer experience bukan sekadar syntax sugar, aspek developer experience lebih mudah dinilai saat client code Anda singkat, jelas, dan mudah direview.
Full clients mengutamakan kecepatan handoff
openapi-generator, hey-api, Orval, dan Kubb semuanya mencoba melakukan lebih dari sekadar types. Ini bisa membantu saat Anda ingin request methods, models, dan plumbing di-generate bersamaan, terutama dalam handoff besar antara tim backend dan frontend. Risikonya jelas terlihat pada benchmark di atas: lebih banyak file yang di-generate, runtime surface yang lebih luas, dan potensi build friction saat spec semakin besar.
Tanpa codegen memudahkan refactor lokal
Typed request builders dan fetch wrappers bekerja dengan baik jika satu codebase mengelola kedua sisi shape dan perubahan API terkoordinasi dengan ketat. Kekurangannya adalah disiplin maintenance. Semakin banyak tim dan repository di antara producer dan consumer, semakin besar kemungkinan request layer buatan sendiri mengalami drift kecuali Anda menerapkan contract tests secara agresif.
Keputusan utamanya bukan soal ideologi. Jika budget bundle Anda ketat, pure types sangat menarik. Jika tim Anda ingin scaffolding maksimal dan bisa menampung output-nya, full clients akan mengurangi setup time. Jika Anda ingin komponen seminimal mungkin dan bisa menjaga contract tetap dekat, no-codegen request builders bisa menjadi pilihan trade-off internal yang tepat.
Membuat Thin Typed Client dengan Fetch atau Axios

Thin wrapper adalah titik di mana generator berhenti dan code aplikasi Anda dimulai. Wrapper ini harus mengekspos satu fungsi per operasi, menerima params dan objek query yang bertipe, lalu meneruskan panggilan ke fetch atau instance yang di-inject axios tanpa mencoba menjadi terlalu kompleks. Di sebagian besar setup produksi, layer tersebut biasanya hanya sekitar 30–60 baris karena tipe yang di-generate sudah mencakup sebagian besar strukturnya.
Berikut mental model yang bisa diandalkan:
- Path params tetap bertipe agar
/users/{id}tidak bisa dipanggil tanpaid. - Objek query tetap bertipe agar filter opsional tidak menjadi berantakan.
- Response body tetap memiliki tipe data sehingga parsing code bisa mempercayai struktur spesifik yang diharapkan.
Wrapper seperti itu sengaja dibuat sederhana. Ia tidak boleh menambahkan fitur retry, transform, atau kebijakan auth jika itu seharusnya di tempat lain. Tugasnya hanya memindahkan request dari operasi bertipe ke transport layer, lalu mengembalikan hasil bertipe tersebut.
Jaga agar wrapper tetap sederhana dan minim dependency, agar setiap perubahan codegen di masa depan tidak merusak seluruh aplikasi Anda.
Kesalahan umum yang sering terjadi adalah menambal ketidakcocokan dengan as any saat tipe yang dihasilkan tidak sesuai dengan signature wrapper lama. Hal ini hanya memberikan build yang sukses tapi aplikasi yang rapuh. Ini juga menyembunyikan pelanggaran kontrak yang justru ingin Anda temukan lewat generator.
Bagi tim yang lebih suka Axios, polanya tetap sama, hanya implementasi transport-nya yang berbeda. Bagi tim yang menginginkan code sisi browser yang lebih simpel, fetch seringkali sudah cukup. Bagian terpentingnya adalah fungsi request menerima tipe path yang dihasilkan dan mengembalikan response bertipe, bukan objek dengan struktur longgar yang baru diolah kemudian.
Jika Anda memanfaatkan celah ini dengan baik, openapi typescript memberikan pembagian tugas yang bersih. Schema ada di spec, transport ada di wrapper, dan aplikasi melihat operasi bertipe alih-alih request code yang ad hoc.
Tambah Runtime Validation dengan zod, ajv, atau io-ts
Tipe TypeScript hilang saat runtime, dan jaringan tidak peduli seberapa yakin editor Anda. Itu sebabnya pola aman bukan “generate types lalu berharap”, melainkan “generate types, lalu validasi di edge tempat data tak tepercaya masuk ke aplikasi”. Schema yang dihasilkan tetap jadi source of truth, dan library validasi seperti zod, ajv, dan io-ts menangani boundary check yang tidak bisa dilakukan tipe compile-time.
Validasi di titik data masuk
Untuk aplikasi React, edge biasanya tepat setelah request selesai dan sebelum payload masuk ke state. Untuk server, sebelum payload ditulis ke database atau diserahkan ke business rule. Aturannya sederhana: jaga validasi tetap dekat dengan boundary dan jangan sebar pengecekan manual di seluruh fitur code.
Sebuah zod shape dapat mencerminkan shape response yang dihasilkan tanpa menggantikannya:
import { z } from "zod";
const WeatherForecastSchema = z.object({
date: z.string(),
temperatureC: z.number(),
summary: z.string().nullable(),
temperatureF: z.number().optional(),
});
Contoh itu memvalidasi field yang ditandai opsional oleh schema, dan menjaga runtime check tetap selaras dengan yang dihasilkan generator. ajv adalah pilihan kuat jika Anda menginginkan validasi JSON Schema throughput tinggi di server, sementara io-ts tetap cocok untuk tim yang sudah terbiasa dengan fp-ts gaya komposisi.
Kesalahan fatal adalah melakukan validasi terlalu lambat. Jika payload masuk ke aplikasi Anda terlebih dahulu, sistem tipe sudah terlewati dan bug punya tempat untuk bersembunyi. Panduan singkat tentang unit test untuk JavaScript sangat cocok dengan pola pikir ini, karena unit test dan boundary validation bekerja paling baik saat keduanya menangkap asumsi yang salah sejak dini.
Layering yang bersih membuatnya mudah diprediksi. OpenAPI TypeScript menghasilkan contract, validator memeriksa runtime payload, dan aplikasi code Anda hanya melihat data yang lolos dari kedua tahap tersebut. Ini adalah boundary yang jauh lebih baik daripada sekadar mengandalkan static type untuk mengontrol response yang tidak terpercaya.
Integrasikan Generation, Validation, dan Contract Tests ke CI

Pipeline yang berkelanjutan mengubah contract menjadi gerbang validasi, bukan sekadar saran. Regenerate tipe, gagal jika ada drift, jalankan tsc --noEmit, dan uji bentuk API terhadap mock atau contract tool sebelum melakukan merge. Jika Anda mengunci versi generator di package.json, dua engineer tidak akan tidak sengaja menghasilkan output berbeda dari spec yang sama.
Struktur GitHub Actions yang simpel
Workflow praktisnya seperti ini:
- Ambil spec dari repo atau source hasil generate.
- Regenerate tipe-nya.
- Gagalkan job jika
git diffmenunjukkan perubahan. - Jalankan
tsc --noEmit. - Jalankan contract test terhadap mock server seperti Prism atau pengecekan berbasis Spectral.
Perbedaan utama antara contract test dan snapshot test adalah scope-nya. Snapshot sering kali hanya memberi tahu bahwa file berubah. Contract test memberi tahu apakah bentuk datanya masih berperilaku sesuai spec.
Mock server sangat berguna saat pekerjaan backend dan frontend terpisah oleh waktu atau batas tim. Ini memberi code surface API yang bisa diprediksi sambil tetap mengecek contract asli, bukan fixture hard-coded. Panduan setup continuous integration berguna sebagai referensi jika tim Anda masih butuh baseline CI yang bersih dan repeatable.
Mengunci versi generator mencegah salah satu kegagalan paling merepotkan di pipeline codegen: output skew yang tak terlihat. Jika satu developer meng-upgrade generator secara lokal dan yang lain tidak, file hasil generate bisa jadi sumber noise, bukan signal. CI harus membuat itu mustahil terjadi.
Hasilnya adalah pipeline di mana perubahan schema, type generation, compiler checks, dan contract tests saling memperkuat satu sama lain. Itulah yang membuat workflow menjadi akurat.
Pipeline yang Maintainable, Performa, dan Checklist Akhir

Pipeline yang bertahan adalah yang memiliki tata kelola yang stabil. Berikan versi pada spec, review perubahan schema seperti code, pin generator-nya, dan dokumentasikan cara persetujuan breaking changes. Jika prosesnya tidak jelas, orang akan mencari jalan pintas, dan akhirnya tipe yang di-generate hanya jadi hiasan, bukan penegakan aturan.
Beberapa faktor performa yang benar-benar penting
Incremental generation sangat membantu pada monorepo di mana spec sering berubah tetapi hanya satu package yang menggunakannya. tsc --incremental dapat mengurangi beban kerja compiler yang berulang, dan menonaktifkan output flags yang tidak diperlukan pada production build akan menjaga surface yang di-generate tetap kecil. Praktiknya, keuntungan terbesar tetaplah faktor sosial, bukan teknis, karena pipeline yang dapat diprediksi akan lebih sering dijalankan daripada yang terlalu kompleks.
Checklist di bawah ini sangat penting untuk disimpan:
- Versi pinning: Kunci
openapi-typescriptversi dipackage.jsonagar output tidak berbeda antar mesin. - Review skema: Anggap perubahan spec sebagai perubahan kontrak yang perlu direview, bukan sekadar housekeeping.
- Deteksi drift: Regenerate di CI dan buat fail jika ada diff.
- Validasi edge: Parse payload yang tidak terpercaya sebelum masuk ke app state atau persistence.
- Contract testing: Jalankan pengecekan berbasis mock untuk membuktikan code consumer tetap sesuai dengan skema.
- Kebijakan breaking-change: Catat siapa yang menyetujui perubahan shape dan bagaimana klien diberi tahu.
Pipeline yang menyertakan gate tersebut tidak hanya men-generate types, tapi juga membuat kontraknya terlihat jelas. Visibilitas inilah yang mencegah tim hanya percaya pada file yang sekadar terlihat aman.
Jika Anda merilis Capacitor atau aplikasi Electron dan ingin update pipeline Anda berjalan dengan disiplin yang sama, Capgo memberi Anda cara praktis untuk memperbarui JavaScript, CSS, copy, config, dan asset dengan cepat tanpa menunggu review app store. Kunjungi Capgo untuk melihat bagaimana signed bundles, rollback protection, dan kontrol rilis bekerja dalam proses rilis yang butuh kecepatan tanpa kehilangan kendali.