1. Prinsip-prinsip REST
REST (Representational State Transfer) adalah arsitektur software yang diperkenalkan oleh Roy Fielding dalam disertasinya tahun 2000. REST bukan standar, melainkan sekumpulan prinsip desain yang digunakan untuk membangun web services yang scalable, maintainable, dan interoperable.
API yang mengikuti prinsip REST disebut RESTful API. Mayoritas API publik saat ini — termasuk Twitter, GitHub, Google Maps, dan Stripe — menggunakan arsitektur REST karena kesederhanaan dan skalabilitasnya.
6 Prinsip Utama REST
| Prinsip | Penjelasan | Contoh Implementasi |
|---|---|---|
| Client-Server | Client dan server terpisah — masing-masing bisa berkembang secara independen | Frontend React terpisah dari backend Node.js |
| Stateless | Setiap request harus berisi semua informasi yang dibutuhkan server — tidak ada session state | Token JWT dikirim di setiap request header |
| Cacheable | Response harus menyatakan apakah data bisa di-cache atau tidak | Header Cache-Control, ETag |
| Uniform Interface | Antarmuka yang konsisten menggunakan URL dan HTTP methods standar | GET /users, POST /users |
| Layered System | Client tidak perlu tahu apakah berbicara langsung dengan server atau melalui proxy/CDN | API Gateway, load balancer, CDN |
| Code on Demand (opsional) | Server bisa mengirim executable code ke client | JavaScript di response (jarang digunakan) |
┌───────────────────────────────────────────────────────────┐ │ REST API ARCHITECTURE │ │ │ │ ┌──────────┐ ┌───────────────────────────────┐ │ │ │ Client │ │ REST API Server │ │ │ │ │ │ │ │ │ │ Browser │ HTTP │ ┌──────────┐ ┌───────────┐ │ │ │ │ Mobile │◄───────►│ │ Router │ │ Middleware │ │ │ │ │ CLI │ Request │ └────┬─────┘ └─────┬─────┘ │ │ │ │ │ │ │ │ │ │ │ └──────────┘ │ ┌────▼─────────────▼─────┐ │ │ │ │ │ Controllers │ │ │ │ │ │ (Business Logic) │ │ │ │ │ └────────────┬────────────┘ │ │ │ │ │ │ │ │ │ ┌────────────▼────────────┐ │ │ │ │ │ Database Layer │ │ │ │ │ │ (PostgreSQL/MongoDB) │ │ │ │ │ └─────────────────────────┘ │ │ │ └───────────────────────────────┘ │ └───────────────────────────────────────────────────────────┘
REST bukan satu-satunya pilihan untuk API. GraphQL cocok untuk data yang kompleks dan butuh query fleksibel. gRPC cocok untuk komunikasi antar-microservice berperforma tinggi. Namun, REST tetap pilihan terbaik untuk sebagian besar kasus karena kesederhanaan, dokumentasi luas, dan kompatibilitas universal.
2. HTTP Methods
HTTP methods (juga disebut HTTP verbs) mendefinisikan operasi apa yang ingin dilakukan client terhadap resource. Dalam REST API, setiap operasi CRUD dipetakan ke HTTP method yang sesuai.
Mapping HTTP Methods ke Operasi CRUD
| HTTP Method | Operasi | URL Contoh | Berhasil | Aman? | Idempoten? |
|---|---|---|---|---|---|
GET | Read (ambil data) | GET /api/users | 200 OK | ✅ Ya | ✅ Ya |
POST | Create (buat baru) | POST /api/users | 201 Created | ❌ Tidak | ❌ Tidak |
PUT | Update (ganti seluruh) | PUT /api/users/1 | 200 OK | ❌ Tidak | ✅ Ya |
PATCH | Update (sebagian) | PATCH /api/users/1 | 200 OK | ❌ Tidak | ❌ Tidak |
DELETE | Delete (hapus) | DELETE /api/users/1 | 204 No Content | ❌ Tidak | ✅ Ya |
HEAD | Seperti GET tanpa body | HEAD /api/users | 200 OK | ✅ Ya | ✅ Ya |
OPTIONS | Info methods yang tersedia | OPTIONS /api/users | 200 OK | ✅ Ya | ✅ Ya |
- Aman (Safe): Method tidak mengubah data di server — hanya membaca.
- Idempoten: Memanggil method yang sama berkali-kali menghasilkan hasil yang sama. Misalnya
DELETE /users/1— meskipun dipanggil 5 kali, hasilnya tetap: user 1 terhapus. - POST tidak idempoten: Memanggil
POST /usersberkali-kali akan membuat banyak user baru.
Contoh Penggunaan
# ── GET: Mengambil daftar pengguna ──
GET /api/v1/users?page=1&limit=10 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# Response:
# HTTP/1.1 200 OK
# Content-Type: application/json
{
"status": "success",
"data": [
{ "id": 1, "name": "Budi", "email": "budi@mail.com" },
{ "id": 2, "name": "Sari", "email": "sari@mail.com" }
],
"pagination": { "page": 1, "limit": 10, "total": 2 }
}
# ── POST: Membuat pengguna baru ──
POST /api/v1/users HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
{
"name": "Andi Pratama",
"email": "andi@mail.com",
"password": "rahasia123"
}
# Response:
# HTTP/1.1 201 Created
# Location: /api/v1/users/3
{ "status": "success", "data": { "id": 3, "name": "Andi Pratama", "email": "andi@mail.com" } }
# ── PUT: Mengganti seluruh data pengguna ──
PUT /api/v1/users/3 HTTP/1.1
Content-Type: application/json
{
"name": "Andi Pratama",
"email": "andi.baru@mail.com",
"password": "passwordBaru456"
}
# ┶ PATCH: Mengubah sebagian data ──
PATCH /api/v1/users/3 HTTP/1.1
Content-Type: application/json
{ "email": "andi.update@mail.com" }
# ── DELETE: Menghapus pengguna ──
DELETE /api/v1/users/3 HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# Response:
# HTTP/1.1 204 No Content
3. HTTP Status Codes
HTTP status code memberitahu client hasil dari request-nya. Menggunakan status code yang tepat adalah bagian penting dari desain REST API yang baik. Status code dibagi menjadi 5 kategori berdasarkan digit pertama.
Kategori Status Code
| Kategori | Range | Arti |
|---|---|---|
| 🟢 Informational | 1xx | Request diterima, proses berlanjut |
| 🟢 Success | 2xx | Request berhasil diproses |
| 🟡 Redirection | 3xx | Perlu redirect ke URL lain |
| 🔴 Client Error | 4xx | Kesalahan dari sisi client |
| 🔴 Server Error | 5xx | Kesalahan dari sisi server |
Status Code yang Sering Digunakan dalam REST API
| Code | Nama | Kapan Digunakan |
|---|---|---|
200 | OK | Request berhasil — GET, PUT, PATCH |
201 | Created | Resource baru berhasil dibuat — POST |
204 | No Content | Request berhasil, tidak ada body response — DELETE |
301 | Moved Permanently | Resource telah pindah secara permanen |
400 | Bad Request | Data request tidak valid (format salah, field kurang) |
401 | Unauthorized | Client belum terotentikasi (tidak punya token) |
403 | Forbidden | Client terotentikasi tapi tidak punya izin |
404 | Not Found | Resource tidak ditemukan |
405 | Method Not Allowed | HTTP method tidak didukung untuk URL ini |
409 | Conflict | Konflik — misalnya email sudah terdaftar |
422 | Unprocessable Entity | Format benar tapi data tidak bisa diproses |
429 | Too Many Requests | Rate limit terlampaui |
500 | Internal Server Error | Error tak terduga di server |
502 | Bad Gateway | Server upstream mengembalikan response tidak valid |
503 | Service Unavailable | Server sedang maintenance atau overload |
Kesalahan umum: mengembalikan 200 OK untuk semua response termasuk error, lalu menandai error di dalam body JSON. Ini melanggar konvensi REST. Gunakan status code yang tepat sehingga client bisa memproses response secara otomatis.
4. URL Design & Naming Conventions
Desain URL yang baik membuat API intuitif dan mudah digunakan. Ada beberapa konvensi yang harus diikuti agar API Anda konsisten dan profesional.
Konvensi URL Naming
| Aturan | ✅ Benar | ❌ Salah |
|---|---|---|
| Gunakan noun (kata benda), bukan verb | GET /api/users | GET /api/getUsers |
| Gunakan plural untuk collection | /api/articles | /api/article |
| Gunakan lowercase dan hyphens | /api/user-profiles | /api/UserProfiles |
| Hindari file extension | /api/users/1 | /api/users/1.json |
| Hindari trailing slash | /api/users | /api/users/ |
| Gunakan nesting untuk relasi | /api/users/1/orders | /api/userOrders/1 |
| Jangan terlalu dalam (max 3 level) | /api/users/1/orders/5 | /api/users/1/orders/5/items/3 |
Contoh Desain URL yang Baik
# ── Resource Collection ── GET /api/v1/users # Ambil semua user POST /api/v1/users # Buat user baru # ── Single Resource ── GET /api/v1/users/42 # Ambil user ID 42 PUT /api/v1/users/42 # Update user 42 (full) PATCH /api/v1/users/42 # Update user 42 (partial) DELETE /api/v1/users/42 # Hapus user 42 # ── Nested Resources (relasi) ── GET /api/v1/users/42/orders # Semua order milik user 42 POST /api/v1/users/42/orders # Buat order baru untuk user 42 GET /api/v1/users/42/orders/7 # Order 7 milik user 42 # ── Sub-resource Operations ── POST /api/v1/articles/5/comments # Tambah komentar pada artikel 5 GET /api/v1/articles/5/comments # Ambil semua komentar artikel 5 # ── Actions (ketika CRUD tidak cukup) ── POST /api/v1/users/42/activate # Aktifkan user 42 POST /api/v1/orders/7/cancel # Batalkan order 7 POST /api/v1/articles/5/publish # Publikasikan artikel 5 # ── Search & Filter ── GET /api/v1/articles?category=teknologi&sort=-created_at GET /api/v1/users?search=budi&role=admin&page=2 # ── WRONG: Contoh URL yang buruk ── # GET /api/getUser ← menggunakan verb # GET /api/user ← singular # GET /api/all-users ← prefix tidak perlu # POST /api/users/create ← verb di URL # GET /api/Users/Posts ← PascalCase
5. API Versioning
API versioning memungkinkan Anda merilis perubahan yang breaking tanpa merusak client yang sudah ada. Setiap versi API berjalan secara paralel sehingga client bisa migrate sesuai jadwal mereka.
Strategi Versioning
| Strategi | Contoh | Kelebihan | Kekurangan |
|---|---|---|---|
| URL Path (populer) | /api/v1/users |
Jelas, mudah di-cache, mudah di-route | URL berubah antar versi |
| Query Parameter | /api/users?version=1 |
URL tetap sama | Kurang umum, sulit di-cache |
| Custom Header | Api-Version: 1 |
URL bersih | Tidak terlihat di URL, perlu dokumentasi |
| Content Negotiation | Accept: application/vnd.api.v1+json |
Sesuai standar HTTP | Kompleks, sulit di-debug |
const express = require('express');
const app = express();
app.use(express.json());
// ═══════════════════════════════════════
// Strategi 1: URL Path Versioning
// ═══════════════════════════════════════
// API v1 — response lama (legacy format)
app.get('/api/v1/users', (req, res) => {
res.json({
users: [
{ id: 1, name: 'Budi', email: 'budi@mail.com' }
]
});
});
// API v2 — response baru (dengan metadata dan pagination)
app.get('/api/v2/users', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
res.json({
status: 'success',
meta: {
version: '2.0',
timestamp: new Date().toISOString()
},
data: {
items: [
{ id: 1, nama_lengkap: 'Budi Santoso', email: 'budi@mail.com' }
],
pagination: {
halaman: page,
per_halaman: limit,
total: 1,
total_halaman: 1
}
}
});
});
// ═══════════════════════════════════════
// Strategi 2: Router Modular per Versi
// ═══════════════════════════════════════
const userRoutesV1 = require('./routes/v1/users');
const userRoutesV2 = require('./routes/v2/users');
app.use('/api/v1/users', userRoutesV1);
app.use('/api/v2/users', userRoutesV2);
// ═══════════════════════════════════════
// Header versioning (untuk API internal)
// ═══════════════════════════════════════
app.use((req, res, next) => {
const version = req.headers['api-version'] || 'v1';
req.apiVersion = version;
next();
});
6. Pagination, Filtering & Sorting
Ketika API mengembalikan data dalam jumlah besar, pagination (paginasi) sangat penting untuk menjaga performa dan menghemat bandwidth. Selain pagination, filtering dan sorting memungkinkan client mengambil data yang tepat sesuai kebutuhan.
Strategi Pagination
| Strategi | Parameter | Cocok Untuk | Contoh |
|---|---|---|---|
| Offset-based | page & limit | Data statis, admin panel | ?page=2&limit=10 |
| Cursor-based | cursor & limit | Data real-time, infinite scroll | ?cursor=eyJpZCI6MTB9&limit=10 |
// ═══════════════════════════════════════
// Endpoint dengan fitur lengkap
// GET /api/v1/articles?category=tech&sort=-created_at&page=1&limit=10
// ═══════════════════════════════════════
app.get('/api/v1/articles', (req, res) => {
let hasil = [...artikelDB];
// ── Filtering ──
if (req.query.category) {
hasil = hasil.filter(a => a.category === req.query.category);
}
if (req.query.author) {
hasil = hasil.filter(a =>
a.author.toLowerCase().includes(req.query.author.toLowerCase())
);
}
if (req.query.status) {
hasil = hasil.filter(a => a.status === req.query.status);
}
if (req.query.search) {
const keyword = req.query.search.toLowerCase();
hasil = hasil.filter(a =>
a.title.toLowerCase().includes(keyword) ||
a.body.toLowerCase().includes(keyword)
);
}
// ── Sorting (prefix "-" untuk descending) ──
const sortField = (req.query.sort || 'created_at').replace('-', '');
const sortOrder = req.query.sort?.startsWith('-') ? -1 : 1;
hasil.sort((a, b) => {
if (a[sortField] < b[sortField]) return -1 * sortOrder;
if (a[sortField] > b[sortField]) return 1 * sortOrder;
return 0;
});
// ── Pagination ──
const halaman = parseInt(req.query.page) || 1;
const limit = Math.min(parseInt(req.query.limit) || 10, 100); // max 100
const totalData = hasil.length;
const totalHalaman = Math.ceil(totalData / limit);
const mulai = (halaman - 1) * limit;
hasil = hasil.slice(mulai, mulai + limit);
// ── Response dengan metadata ──
res.json({
status: 'success',
data: hasil,
pagination: {
halaman: halaman,
per_halaman: limit,
total_data: totalData,
total_halaman: totalHalaman,
halaman_berikutnya: halaman < totalHalaman ? halaman + 1 : null,
halaman_sebelumnya: halaman > 1 ? halaman - 1 : null
},
links: {
self: `/api/v1/articles?page=${halaman}&limit=${limit}`,
first: `/api/v1/articles?page=1&limit=${limit}`,
last: `/api/v1/articles?page=${totalHalaman}&limit=${limit}`,
next: halaman < totalHalaman
? `/api/v1/articles?page=${halaman + 1}&limit=${limit}` : null,
prev: halaman > 1
? `/api/v1/articles?page=${halaman - 1}&limit=${limit}` : null
}
});
});
7. Autentikasi & Otorisasi
Autentikasi memverifikasi identitas client (siapa Anda?), sedangkan otorisasi menentukan hak akses (apa yang boleh Anda lakukan?). Dua metode autentikasi yang paling umum untuk REST API adalah API Key dan JWT (JSON Web Token).
Perbandingan Metode Autentikasi
| Metode | Cara Kerja | Cocok Untuk | Keamanan |
|---|---|---|---|
| API Key | Key dikirim di header atau query | API publik, integrasi pihak ketiga | 🟡 Sedang |
| JWT (Bearer Token) | Token dikirim di header Authorization | Web app, mobile app, SPA | 🟢 Tinggi |
| OAuth 2.0 | Alur authorization code | Login social, ekosistem besar | 🟢 Tinggi |
| Session Cookie | Cookie dengan session ID | Server-rendered web app | 🟢 Tinggi |
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const JWT_SECRET = process.env.JWT_SECRET || 'rahasia-super-aman';
const JWT_EXPIRES = '24h';
// ═══════════════════════════════════════
// Endpoint: Register
// POST /api/v1/auth/register
// ═══════════════════════════════════════
app.post('/api/v1/auth/register', async (req, res) => {
const { nama, email, password } = req.body;
// Validasi input
if (!nama || !email || !password) {
return res.status(400).json({
status: 'error',
message: 'Nama, email, dan password wajib diisi'
});
}
// Cek apakah email sudah terdaftar
const existing = users.find(u => u.email === email);
if (existing) {
return res.status(409).json({
status: 'error',
message: 'Email sudah terdaftar'
});
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 12);
// Simpan user
const newUser = {
id: users.length + 1,
nama,
email,
password: hashedPassword,
role: 'user',
created_at: new Date().toISOString()
};
users.push(newUser);
// Buat JWT token
const token = jwt.sign(
{ id: newUser.id, email: newUser.email, role: newUser.role },
JWT_SECRET,
{ expiresIn: JWT_EXPIRES }
);
res.status(201).json({
status: 'success',
data: {
user: { id: newUser.id, nama, email },
token: token
}
});
});
// ═══════════════════════════════════════
// Endpoint: Login
// POST /api/v1/auth/login
// ═══════════════════════════════════════
app.post('/api/v1/auth/login', async (req, res) => {
const { email, password } = req.body;
const user = users.find(u => u.email === email);
if (!user || !(await bcrypt.compare(password, user.password))) {
return res.status(401).json({
status: 'error',
message: 'Email atau password salah'
});
}
const token = jwt.sign(
{ id: user.id, email: user.email, role: user.role },
JWT_SECRET,
{ expiresIn: JWT_EXPIRES }
);
res.json({
status: 'success',
data: {
user: { id: user.id, nama: user.nama, email: user.email },
token: token
}
});
});
// ═══════════════════════════════════════
// Middleware: Verifikasi Token
// ═══════════════════════════════════════
const autentikasi = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({
status: 'error',
message: 'Token tidak ditemukan. Silakan login.'
});
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
return res.status(401).json({
status: 'error',
message: 'Token tidak valid atau sudah kedaluwarsa'
});
}
};
// Middleware: Cek Role
const izinkanRole = (...roles) => {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({
status: 'error',
message: 'Anda tidak memiliki akses ke resource ini'
});
}
next();
};
};
// ═══════════════════════════════════════
// Protected Routes
// ═══════════════════════════════════════
app.get('/api/v1/profile', autentikasi, (req, res) => {
res.json({ status: 'success', user: req.user });
});
// Hanya admin yang bisa menghapus
app.delete('/api/v1/users/:id',
autentikasi,
izinkanRole('admin'),
(req, res) => {
// Hapus user...
res.json({ status: 'success', message: 'User dihapus' });
}
);
8. Error Handling yang Baik
Response error yang konsisten dan informatif sangat penting agar client dapat menangani error dengan baik. Format error yang terstruktur akan menghemat waktu developer yang menggunakan API Anda.
Format Error Response yang Baik
// ✅ Format error yang BAIK (terstruktur & konsisten)
{
"status": "error",
"error": {
"code": "VALIDATION_ERROR",
"message": "Data yang dikirim tidak valid",
"details": [
{
"field": "email",
"message": "Format email tidak valid",
"value": "budi-at-mail.com"
},
{
"field": "password",
"message": "Password minimal 8 karakter",
"value": "****"
}
]
},
"meta": {
"timestamp": "2026-06-25T10:30:00Z",
"request_id": "req_abc123xyz"
}
}
// ── Contoh error berbagai skenario ──
// 400 Bad Request
{
"status": "error",
"error": {
"code": "BAD_REQUEST",
"message": "Request body tidak valid. Pastikan Content-Type: application/json"
}
}
// 401 Unauthorized
{
"status": "error",
"error": {
"code": "UNAUTHORIZED",
"message": "Token autentikasi tidak ditemukan atau tidak valid"
}
}
// 403 Forbidden
{
"status": "error",
"error": {
"code": "FORBIDDEN",
"message": "Anda tidak memiliki izin untuk mengakses resource ini"
}
}
// 404 Not Found
{
"status": "error",
"error": {
"code": "NOT_FOUND",
"message": "Resource dengan ID 42 tidak ditemukan"
}
}
// 409 Conflict
{
"status": "error",
"error": {
"code": "CONFLICT",
"message": "Email 'budi@mail.com' sudah terdaftar"
}
}
// 429 Too Many Requests
{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Terlalu banyak request. Coba lagi dalam 60 detik.",
"retry_after": 60
}
}
Global Error Handler
// Global error handler middleware (Express)
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500;
const errorCode = err.code || 'INTERNAL_ERROR';
// Log error untuk developer
console.error({
timestamp: new Date().toISOString(),
method: req.method,
url: req.url,
status: statusCode,
message: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
requestId: req.requestId
});
// Response untuk client
res.status(statusCode).json({
status: 'error',
error: {
code: errorCode,
message: statusCode === 500
? 'Terjadi kesalahan internal. Silakan coba lagi nanti.'
: err.message
},
meta: {
timestamp: new Date().toISOString(),
request_id: req.requestId
}
});
});
9. Dokumentasi API (OpenAPI/Swagger)
Dokumentasi yang baik adalah kunci keberhasilan API. Tanpa dokumentasi, developer lain tidak akan tahu cara menggunakan API Anda. Standar OpenAPI Specification (sebelumnya Swagger) adalah format paling populer untuk mendokumentasikan REST API.
Manfaat Dokumentasi API
| Manfaat | Penjelasan |
|---|---|
| Mempercepat Onboarding | Developer baru bisa langsung mulai menggunakan API tanpa bertanya |
| Self-service | Developer bisa mencoba API langsung dari dokumentasi |
| Client SDK Generation | Tools seperti openapi-generator bisa membuat SDK otomatis |
| Testing | Contract testing bisa dilakukan dari spesifikasi OpenAPI |
| Konsistensi | Dokumentasi menjadi "kontrak" antara frontend dan backend team |
Contoh Spesifikasi OpenAPI
openapi: 3.0.3
info:
title: BeebaneLabs API
description: API untuk platform tutorial BeebaneLabs
version: 1.0.0
contact:
name: BeebaneLabs
url: https://beebanelabs.pages.dev
license:
name: MIT
servers:
- url: https://api.beebanelabs.dev/v1
description: Production
- url: http://localhost:3000/v1
description: Development
paths:
/articles:
get:
summary: Mendapatkan daftar artikel
description: Mengembalikan daftar artikel dengan pagination, filter, dan sorting
tags: [Articles]
parameters:
- name: page
in: query
schema:
type: integer
default: 1
description: Nomor halaman
- name: limit
in: query
schema:
type: integer
default: 10
maximum: 100
description: Jumlah item per halaman
- name: category
in: query
schema:
type: string
description: Filter berdasarkan kategori
- name: sort
in: query
schema:
type: string
default: "-created_at"
description: "Sorting (prefix - untuk descending)"
responses:
'200':
description: Berhasil mengambil daftar artikel
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: success
data:
type: array
items:
$ref: '#/components/schemas/Article'
pagination:
$ref: '#/components/schemas/Pagination'
post:
summary: Membuat artikel baru
tags: [Articles]
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [title, body]
properties:
title:
type: string
example: "Tutorial REST API"
body:
type: string
example: "Isi artikel di sini..."
category:
type: string
example: "web-development"
responses:
'201':
description: Artikel berhasil dibuat
'400':
description: Data tidak valid
'401':
description: Tidak terotentikasi
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
Article:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: "Tutorial REST API"
body:
type: string
category:
type: string
author:
type: string
created_at:
type: string
format: date-time
Pagination:
type: object
properties:
halaman:
type: integer
example: 1
per_halaman:
type: integer
example: 10
total_data:
type: integer
example: 42
total_halaman:
type: integer
example: 5
- Swagger UI — Dokumentasi interaktif berbasis browser (paling populer)
- Redoc — Dokumentasi dengan tampilan lebih elegan dan responsif
- Postman — Buat dan bagikan dokumentasi langsung dari collection
- Stoplight Studio — Editor visual untuk OpenAPI Specification
- Scalar — Alternatif modern untuk Swagger UI dengan UI lebih baik
10. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang REST API Design: