Dokumentasi API dengan Swagger & OpenAPI
Kita sudah membahas bagaimana REST API dirancang di Rest API Design Guidelines. Sekarang muncul pertanyaan berikutnya: setelah API selesai dibangun, bagaimana orang lain tahu cara memakainya? Jawaban idealnya bukan lewat dokumen Word yang cepat basi, melainkan lewat dokumentasi yang di-generate langsung dari kode. Artikel ini membahas dua nama yang sering tertukar — Swagger dan OpenAPI — dan bagaimana springdoc-openapi membuat dokumentasi API Spring Boot muncul otomatis sekaligus bisa diuji langsung dari browser.
Kenapa Dokumentasi API Penting
API yang tak terdokumentasi praktis tidak bisa dipakai. Klien (frontend, aplikasi mobile, atau tim lain) tidak bisa menebak bahwa endpoint bernama GET /api/v1/orders memerlukan parameter status bertipe enum, atau bahwa POST /api/v1/orders mengembalikan 201 dengan struktur {orderId, amount, status}. Setiap kali mereka menebak, ada kemungkinan salah — dan kesalahan itu berujung pada iterasi bolak-balik yang membuang waktu.
Masalah dokumentasi manual (menulis Markdown/Word terpisah dari kode) kira-kira seperti ini:
- Cepat usang — kode diubah oleh developer, tapi dokumen lupa diperbarui. Dokumen yang salah lebih berbahaya daripada tidak ada dokumen, karena memberi kepastian yang keliru.
- Beda-beda antar tim — tiap orang punya gaya sendiri; satu tim menulis deskripsi bertele-tele, tim lain cuma menulis satu baris. Tidak ada format standar untuk diprogram.
- Tidak bisa diuji — dokumentasi manual biasanya hanya "teks", tidak punya tombol untuk mencoba endpoint langsung.
Solusinya: generate dokumentasi dari kode. Kontrak (spesifikasi) dan implementasi berada di satu tempat, sehingga keduanya selalu sinkron — kalau kode berubah, spesifikasi ikut berubah. Inilah yang dilakukan springdoc-openapi di ekosistem Spring Boot.
OpenAPI Specification
OpenAPI Specification adalah standar terbuka untuk mendeskripsikan sebuah API — dulu dikenal sebagai Swagger 2.0, lalu berganti nama menjadi OpenAPI setelah dipindah ke OpenAPI Initiative pada tahun 2015. Spesifikasinya ditulis dalam format JSON atau YAML dan bisa dibaca manusia maupun mesin.
Isi sebuah dokumen OpenAPI pada dasarnya menjawab empat pertanyaan:
| Bagian | Yang dijelaskan |
|---|---|
paths | Endpoint apa saja yang tersedia, misal /users, /orders/{id} |
methods | Untuk tiap path: operasi get, post, put, delete, dan sebagainya |
parameters | Parameter path, query, header, atau cookie yang dibutuhkan tiap operasi |
requestBody & responses | Skema (struktur JSON) dari data yang dikirim dan data yang dikembalikan |
components / securitySchemes | Definisi ulang skema (schemas), reusable components, dan mekanisme keamanan seperti Bearer token |
Contoh kecil dokumen OpenAPI dalam YAML untuk sebuah endpoint sederhana:
openapi: 3.0.3
info:
title: Order Service API
version: 1.0.0
description: API untuk membaca dan membuat pesanan.
paths:
/orders:
get:
summary: Daftar pesanan
parameters:
- name: status
in: query
required: false
schema:
type: string
enum: [NEW, PAID, SHIPPED]
responses:
"200":
description: Daftar pesanan berhasil diambil
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Order"
post:
summary: Membuat pesanan baru
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrderInput"
responses:
"201":
description: Pesanan berhasil dibuat
components:
schemas:
Order:
type: object
properties:
id: { type: integer, format: int64 }
amount: { type: number }
status: { type: string }
OrderInput:
type: object
required: [amount]
properties:
amount: { type: number }
Perhatikan bagaimana $ref dipakai untuk menyebut skema yang sama (Order) dari beberapa tempat — ini reusable component yang menghindari pengulangan. Justru dokumen YAML/JSON seperti inilah yang nantinya dihasilkan secara otomatis oleh springdoc-openapi dari kode Anda.
Mengenal Ekosistem Istilah: Swagger vs OpenAPI
Nama Swagger dan OpenAPI sering dipakai bergantian, padahal keduanya berbeda:
| Istilah | Itu apa? | Contoh |
|---|---|---|
OpenAPI Specification | Standar/spesifikasi — aturan format deskripsi API | File openapi.yaml |
Swagger | Tooling/ekosistem dari SmartBear yang awalnya menciptakan standar tersebut | Swagger Editor, Swagger Codegen |
Swagger UI | Antarmuka web yang menampilkan spesifikasi sebagai halaman interaktif yang bisa dieksplorasi dan diuji | Halaman /swagger-ui.html |
springdoc-openapi | Library untuk memproduksi dokumentasi OpenAPI otomatis dari aplikasi Spring Boot, sekaligus menghidangkan Swagger UI | Dependency di pom.xml |
openapi-generator | Generator kode dari spesifikasi (client, server, atau doc) | openapi-generator-cli |
Aturan praktis untuk mengingatnya: OpenAPI adalah bahasanya, Swagger adalah alat-alatnya. Library springdoc-openapi menjembatani keduanya — ia membaca kode Spring Anda, menghasilkan dokumen OpenAPI, lalu menampilkannya lewat Swagger UI.
Implementasi di Spring Boot dengan springdoc-openapi
Cara paling cepat menyalakan dokumentasi di Spring Boot adalah menambahkan satu dependency. Untuk Spring Boot 3.x (pakai jakarta), tambahkan pada pom.xml:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.6</version>
</dependency>
Satu baris dependency ini langsung memberi dua endpoint gratis (lihat Springdoc documentation):
| Endpoint | Isi |
|---|---|
GET /v3/api-docs | Dokumen OpenAPI mentah dalam JSON (spesifikasinya) |
GET /swagger-ui.html | Halaman interaktif Swagger UI untuk mengeksplorasi dan menguji API |
Jalankan aplikasi, buka http://localhost:8080/swagger-ui.html — semua @RestController Anda sudah tampil dengan skema request/response yang otomatis dideteksi. Tanpa menulis satu baris anotasi pun, dokumentasi dasar sudah jadi.
Menyesuaikan Metadata: Bean OpenAPI
Dokumentasi "bawaan" biasanya polos. Untuk memberi title, version, description, dan konfigurasi security scheme, daftarkan sebuah bean OpenAPI:
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI orderServiceOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Order Service API")
.version("1.0.0")
.description("API untuk membaca dan membuat pesanan.")
.license(new License().name("MIT")))
.addServersItem(new Server().url("/").description("Server default"));
}
}
Skema security scheme diatur lewat @SecurityScheme, biasanya diletakkan pada class @Configuration:
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
scheme = "bearer",
bearerFormat = "JWT",
description = "Masukkan token JWT: diawali dengan 'Bearer '")
@Configuration
public class OpenApiSecurityConfig {
// beans tetap di sini
}
bearerAuth adalah nama (kunci) yang nantinya dipakai oleh anotasi @SecurityRequirement(name = "bearerAuth") pada operasi yang butuh autentikasi.
Anotasi Deskriptif: Membuat UI Rapi
Anotasi springdoc yang paling penting adalah @Operation, @ApiResponse, dan @Tag. Ketiganya tidak mengubah perilaku kode — fungsinya murni membuat dokumentasi yang dihasilkan lebih informatif.
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@Tag(name = "Orders", description = "Operasi pengelolaan pesanan")
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
@Operation(
summary = "Ambil detail pesanan",
description = "Mengembalikan detail pesanan berdasarkan id. "
+ "Mengembalikan 404 jika id tidak ditemukan.")
@ApiResponse(responseCode = "200",
description = "Pesanan ditemukan",
content = @Content(schema = @Schema(implementation = OrderDto.class)))
@ApiResponse(responseCode = "404",
description = "Pesanan tidak ditemukan")
@ApiResponse(responseCode = "401",
description = "Token tidak valid atau belum login")
@GetMapping("/{id}")
public ResponseEntity<OrderDto> getOrder(@PathVariable Long id) {
// panggilan ke service, dsb.
return ResponseEntity.ok(orderService.findById(id));
}
}
Mengapa ini penting? Tanpa anotasi, Swagger UI hanya menampilkan nama method Java (getOrder) dan status default yang tak berarti. Dengan @Operation dan @ApiResponse, klien melihat summary yang jelas, deskripsi error yang jujur (404, 401), dan skema yang benar — tanpa perlu membaca kode sumber.
@Tag juga membantu mengelompokkan endpoint yang berkaitan. Alih-alih daftar menu datar, klien melihat kategori seperti Orders, Customers, dan Payments — jauh lebih mudah dinavigasi untuk API yang besar.
Skema Otomatis dari DTO (Jangan dari Entitas)
springdoc menyimpulkan skema request/response dari tipe yang dipakai di controller. Kalau tipe itu adalah entitas JPA, inilah saatnya Anda hati-hati:
- Entitas bisa berisi field internal seperti
passwordHash,version,createdAtyang tidak ingin diekspos. - Entitas punya relasi lazy (
@ManyToOne,@OneToMany) yang saat diserialisasi di luar transaksi bisa melemparLazyInitializationException. - Struktur entitas sering tidak sama dengan bentuk
JSONyang memang ingin Anda jual ke klien.
Praktik yang benar: pakai DTO (Data Transfer Object). Bentuk DTO sesuai dengan bentuk JSON yang dijanjikan, dan tidak pernah membocorkan field internal.
public record OrderDto(
Long id,
BigDecimal amount,
String status,
String customerEmail) {
}
Entitas ke DTO dipetakan di layer service/mapper, bukan di controller langsung. Dengan pola ini, dokumentasi yang muncul di Swagger UI otomatis menjadi dokumen publik yang aman, bukan dump dari struktur database.
Memakai Swagger UI untuk Menguji Endpoint
Keunggulan terbesar Swagger UI adalah ia bukan sekadar "katalog", melainkan juga client untuk mencoba API langsung dari browser:
- Explore — setiap operasi tampil sebagai blok dengan
summary,parameters, dan contohresponse. Buka salah satu blok untuk melihat detail. - "Try it out" — klik tombol ini untuk mengaktifkan mode pengujian; kolom parameter menjadi dapat diedit.
- Isi parameter — masukkan nilai
path/query, dan untukPOST/PUTisi bodyJSONdi editor. - Autentikasi — klik tombol
Authorizedi kanan atas, tempeltoken(misalnyaBearer <token>), dan semua request akan membawa headerAuthorizationsecara otomatis. - Execute — request dikirim ke server sungguhan, lalu respons penuh (
status,headers,body) ditampilkan di bawah blok operasi.
Fitur ini menyelamatkan Anda dari alat seperti Postman untuk kasus sederhana: konfigurasi sudah tersedia, skema sudah diisi, token cukup sekali dimasukkan. Tidak perlu menangkap screenshot — coba sendiri di aplikasi Anda dan rasakan bedanya.
Tip:
Swagger UImemanggil server sungguhan. Fitur ini memudahkan testing, tetapi pastikan Anda mengujinya pada lingkungandevelopment/staging, bukan data produksi yang sensitif — terutama untuk operasiPOST/DELETE.
OpenAPI sebagai Kontrak Tim
Ketika spesifikasi OpenAPI sudah akurat, ia menjadi lebih dari sekadar dokumentasi — ia menjadi kontrak yang bisa diprogram oleh kedua sisi.
Generate Client untuk Frontend
Karena spesifikasi OpenAPI adalah file terstruktur (JSON/YAML), frontend tidak perlu menulis kode HTTP dengan tangan. Gunakan OpenAPI Generator untuk membuat client library langsung dari spesifikasi:
# contoh: generate client TypeScript (fetch / axios)
npx @openapitools/openapi-generator-cli generate \
-i /path/to/openapi.json \
-g typescript-axios \
-o src/api/client
Dari satu file spesifikasi, generator bisa memproduksi client dalam banyak bahasa (typescript-axios, typescript-fetch, dart, kotlin, dan lain-lain). Alternatif yang populer di ekosistem Angular adalah ng-openapi-gen. Keuntungannya: jenis, interface, dan fungsi pemanggil selalu sinkron dengan spesifikasi — karena mereka memang dihasilkan dari spesifikasi tersebut, bukan ditulis tangan lalu diharapkan cocok.
Contract-First vs Code-First
Ada dua cara memproduksi spesifikasi OpenAPI:
| Aspek | Contract-first | Code-first |
|---|---|---|
| Alur | Spesifikasi ditulis dulu, lalu kode mengikutinya | Kode ditulis dulu, spesifikasi dihasilkan dari kode |
| Contoh tooling | swagger-editor, openapi-generator untuk stub server | springdoc-openapi (otomatis) |
| Kelebihan | Kontrak bisa didiskusikan dengan klien sebelum implementasi; klien bisa mulai kerja paralel | Tanpa usaha ekstra, dokumentasi selalu sinkron dengan kode |
| Kekurangan | Butuh disiplin menjaga kode sesuai spesifikasi; bisa ketinggalan dari kode | Kualitas dokumentasi bergantung pada kualitas anotasi; kontrak "baru ada" setelah kode jadi |
| Cocok untuk | Tim besar, API publik/antar-tim, fitur baru yang didesain dulu | Prototipe, API internal, iterasi cepat |
springdoc termasuk pendekatan code-first: spesifikasi di-generate dari kode. Artikel ini fokus ke situ itu. Untuk API publik yang besar, pertimbangkan contract-first agar spesifikasi bisa disetujui klien sebelum implementasi dimulai.
Verifikasi di CI (Opsional)
Ada celah kecil pada code-first: spesifikasi selalu dihasilkan ulang dari kode, jadi secara definisi sinkron. Namun pada contract-first atau saat ada klien yang bergantung pada file spesifikasi yang di-commit, tambahkan langkah di CI untuk memastikan file tersebut tidak usang:
# contoh job GitHub Actions (ringkas)
- name: Regenerate dan bandingkan spesifikasi
run: |
mvn springdoc-openapi-maven-plugin:generate
git diff --exit-code -- src/main/resources/static/openapi.json
Perintah git diff --exit-code membuat build gagal bila file openapi.json berubah (berarti kode baru tanpa pembaruan kontrak). Ini menyelamatkan tim dari "spesifikasi sudah tidak sinkron dengan kode".
Keamanan Dokumentasi
Dokumentasi yang bagus adalah pedang bermata dua: ia memudahkan klien, tapi juga memudahkan penyerang memetakan permukaan serangan Anda. Perhatikan hal-hal berikut:
- Jangan bocorkan skema internal. Selalu tampilkan
DTO, bukan entitas. Field sepertipasswordHashatau detail arsitektur internal tidak pernah layak masuk ke dokumen publik. - Matikan dokumentasi di produksi bila tidak diperlukan.
Swagger UIdiaktifkan via property Spring Boot:
springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false
Nyalakan hanya di profil tertentu, misalnya di dalam blok profil dev pada application.yml — sehingga dokumentasi tetap hidup untuk developer, tapi mati untuk publik produksi.
- Autentikasi Swagger UI. Bila dokumentasi harus ada di produksi (misal untuk operasional internal), lindungi halamannya. Karena
Swagger UIadalah servlet biasa, ia bisa dibatasi lewat konfigurasiSecurityFilterChainSpring Security:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/swagger-ui/**", "/v3/api-docs/**")
.authorizeHttpRequests(auth -> auth.anyRequest().hasRole("ADMIN"));
return http.build();
}
Pendekatan ini memastikan hanya pengguna dengan peran ADMIN yang bisa melihat spesifikasi dan mencoba endpoint dari UI. Lebih detail tentang autentikasi ini dibahas di Session vs JWT dan RBAC Authorization.
Jebakan Umum (Common Pitfalls)
| Jebakan | Dampak | Solusi |
|---|---|---|
| Mengekspos entitas JPA langsung | Bocor field internal (passwordHash) + LazyInitializationException saat serialisasi | Selalu balas lewat DTO |
@Operation/@ApiResponse berlebihan di tiap method | Dokumen membanjiri pembaca dengan detail; summary kehilangan makna | Anotasi pada yang memang butuh konteks; biarkan yang sudah jelas dari nama method |
| Lupa mengganti contoh schema yang dipakai anotasi | Klien melihat struktur lama yang keliru | Pastikan @Schema(implementation = ...) merujuk DTO terbaru |
| Versi spesifikasi tidak konsisten antar modul | openapi: 3.0.3 di satu file, 3.1.0 di file lain — hasil generate berubah perilaku | Samakan versi openapi dan versi springdoc di seluruh modul |
| Dokumentasi aktif di produksi | Membantu penyerang memetakan endpoint | Matikan atau lindungi via Spring Security |
Best Practice
Ringkasan kebiasaan yang menghasilkan dokumentasi yang benar-benar dipakai orang:
- Deskripsi dalam bahasa tim. Tulis
summary/descriptiondengan kalimat yang dipahami rekan satu tim dan klien, bukan jargon internal. Deskripsi yang ambigu justru menimbulkan pertanyaan baru. - Grouping dengan
@Tag. Kelompokkan endpoint berdasarkan domain (Orders,Customers,Payments), bukan berdasarkan class Java. - Dokumentasikan error response. Endpoint yang hanya mendokumentasikan
200memberi kesan seolah tak pernah gagal. Cantumkan400,401,403,404yang memang bisa terjadi — konsisten dengan klasifikasi status code di artikel Anatomi HTTP. - Contoh nilai untuk parameter. Isi
examplepada parameterquery/pathdan@Schema(example = "...")pada field DTO. Contoh nyata jauh lebih membantu daripada tipe data kosong. - Gunakan DTO, bukan entitas. Ini berulang kali disebut karena ini akar dari dokumentasi yang aman dan akurat.
Ringkasan
Dokumentasi API yang baik bukan dokumen terpisah yang cepat basi, melainkan spesifikasi OpenAPI yang di-generate otomatis dari kode dan ditampilkan lewat Swagger UI. Dengan satu dependency springdoc-openapi-starter-webmvc-ui, aplikasi Spring Boot langsung mendapat /v3/api-docs dan /swagger-ui.html; @Operation, @ApiResponse, dan @Tag membuat dokumen itu rapi, sedangkan penggunaan DTO (bukan entitas) menjaganya tetap aman. Spesifikasi yang dihasilkan bisa sekaligus berperan sebagai kontrak tim — untuk generate client frontend, sebagai dasar diskusi contract-first, dan untuk verifikasi di CI. Ingat jebakannya: ekspos DTO, dokumentasikan error, isi contoh nilai, dan jangan biarkan dokumentasi terbuka tanpa pengaman di produksi.
Lanjut membaca
- OpenAPI Specification — standar spesifikasi dan detail seluruh keyword-nya
- springdoc-openapi — dokumentasi resmi library, termasuk konfigurasi lanjutan
- Springdoc di Spring Docs — panduan integrasi dengan ekosistem Spring Boot
- OpenAPI Generator — generate client/server dari spesifikasi
- Rest API Design Guidelines — landasan desain endpoint sebelum didokumentasikan
- JPA & Hibernate ORM — kenapa entitas tidak boleh langsung diekspos, dan peran
DTOdalam serialisasi