Di Part 1 kita sudah kenalan konsep spec-first. Sekarang kita bedah strukturnya: apa saja bagian wajib sebuah file OpenAPI, dan apa fungsi masing-masing. Sebagai contoh kerja, kita pakai notes-api.yaml — spec untuk API catatan sederhana yang akan kita generate jadi kode Go di Part 4.
Struktur Besar
Sebuah file OpenAPI 3.0 punya 4 bagian utama:
openapi: 3.0.3 # versi spesifikasi OpenAPI yang dipakai
info: ... # metadata: judul, deskripsi, versi API
paths: ... # daftar endpoint dan operasinya
components: ... # skema/schema yang dipakai berulang (reusable)
info — Metadata API
info:
title: Notes API
description: >
Contoh API catatan (notes) sederhana untuk belajar OpenAPI spec-first.
Dibangun pelan-pelan di seri "OpenAPI Spec-First untuk Go Developer".
version: 1.0.0
license:
name: MIT
url: https://opensource.org/licenses/MIT
version di sini adalah versi API-nya sendiri (bukan versi file OpenAPI), berguna kalau nanti ada breaking change dan butuh versi baru (v2).
servers dan security
servers:
- url: http://localhost:8080
description: Local development server
security: []
servers mendaftar base URL yang valid untuk API ini — tools seperti Swagger UI pakai ini untuk tahu ke mana request dikirim saat dicoba langsung dari browser.
security: [] di level root berarti secara eksplisit API ini tidak butuh autentikasi apa pun. Ini penting: linter OpenAPI (akan kita pakai di Part 5) akan komplain kalau security tidak didefinisikan sama sekali di suatu operation — karena nggak jelas apakah itu memang publik atau cuma lupa ditulis. Eksplisit [] menghilangkan ambiguitas itu.
paths — Endpoint dan Operasinya
Ini bagian paling besar. Satu path bisa punya beberapa method (get, post, put, delete), dan tiap method adalah satu operation:
paths:
/notes:
get:
operationId: listNotes
tags: [Notes]
summary: Daftar notes dengan pagination
parameters:
- name: page
in: query
schema:
type: integer
minimum: 1
default: 1
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 10
responses:
'200':
description: Daftar notes berhasil diambil
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
data:
type: array
items:
$ref: '#/components/schemas/Note'
meta:
$ref: '#/components/schemas/PaginationMeta'
'400':
$ref: '#/components/responses/BadRequest'
Beberapa hal penting di sini:
operationId— nama unik untuk operation ini. Nanti ini yang jadi nama fungsi Go saat digenerate (listNotes→ListNotes). Wajib unik di seluruh file.parametersdenganin: query— parameter lewat query string (?page=1&limit=10). Ada jugain: path(lihat/notes/{id}di bawah) danin: header.responses— key-nya adalah HTTP status code.$ref: '#/components/responses/BadRequest'memakai ulang definisi response yang didefinisikan sekali dicomponents, supaya tidak copy-paste di setiap endpoint yang bisa mengembalikan 400.
Untuk endpoint yang punya path parameter, parameter itu bisa didefinisikan sekali di level path (berlaku untuk semua method di bawahnya):
/notes/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
get:
operationId: getNote
tags: [Notes]
summary: Detail 1 note
responses:
'200':
description: Note ditemukan
content:
application/json:
schema:
$ref: '#/components/schemas/NoteResponse'
'404':
$ref: '#/components/responses/NotFound'
Untuk post/put, ada tambahan requestBody yang mendeskripsikan bentuk JSON body yang diterima:
post:
operationId: createNote
tags: [Notes]
summary: Buat note baru
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateNoteRequest'
responses:
'201':
description: Note berhasil dibuat
content:
application/json:
schema:
$ref: '#/components/schemas/NoteResponse'
'400':
$ref: '#/components/responses/BadRequest'
components/schemas — Skema yang Dipakai Berulang
Ini "kamus" tipe data yang dirujuk lewat $ref di mana saja dalam file. Keuntungannya: definisi Note cukup ditulis sekali, dipakai di banyak response.
components:
schemas:
Note:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
body:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
required: [id, title, body, created_at, updated_at]
CreateNoteRequest:
type: object
properties:
title:
type: string
minLength: 1
maxLength: 255
body:
type: string
minLength: 1
required: [title, body]
NoteResponse:
type: object
properties:
success:
type: boolean
message:
type: string
data:
$ref: '#/components/schemas/Note'
PaginationMeta:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
ErrorResponse:
type: object
properties:
success:
type: boolean
example: false
message:
type: string
error:
type: string
Perhatikan minLength, maxLength, minimum, maximum — ini bukan cuma dokumentasi, tapi constraint yang nanti bisa divalidasi otomatis oleh tooling (dan jadi dokumentasi yang jelas buat siapa pun yang baca spec ini).
components/responses menyimpan response yang dipakai berulang di banyak endpoint (400 dan 404 di sini):
responses:
BadRequest:
description: Request tidak valid
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
NotFound:
description: Resource tidak ditemukan
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
File Lengkapnya
Setelah semua bagian di atas digabung, api/openapi/notes-api.yaml lengkapnya mendeskripsikan 5 operation: listNotes, createNote, getNote, updateNote, deleteNote — lengkap dengan request, response sukses, dan response error untuk tiap satu.
Spec ini belum menghasilkan satu baris kode Go pun. Di Part 3, kita kenalan dengan ekosistem tools yang akan mengubah file YAML ini jadi types dan interface Go — sebelum di Part 4 kita benar-benar menjalankan generate-nya.
Bagian dari Series: OpenAPI Spec-First untuk Go Developer
Seri 8 bagian: belajar mendesain REST API dengan pendekatan spec-first di Go - menulis kontrak OpenAPI dulu, generate kode, lalu terapkan ke project h...
Lihat Series Lengkap