| 1 | --- |
| 2 | title: "REST (Representational State Transfer)" |
| 3 | term: "apa-itu-rest" |
| 4 | category: "Pemrograman" |
| 5 | tags: ["api", "web", "http", "backend", "restful", "web-service"] |
| 6 | description: "Arsitektur software untuk membuat web services yang menggunakan HTTP methods standar untuk operasi CRUD pada resources." |
| 7 | englishTerm: "Representational State Transfer" |
| 8 | acronym: "REST" |
| 9 | relatedTerms: ["apa-itu-api", "apa-itu-http", "apa-itu-json", "apa-itu-graphql", "apa-itu-crud"] |
| 10 | difficulty: "menengah" |
| 11 | lastmod: 2024-01-15 |
| 12 | published: true |
| 13 | --- |
| 14 | |
| 15 | ## Apa itu REST? |
| 16 | |
| 17 | **REST (Representational State Transfer)** adalah gaya arsitektur untuk membuat web service yang memakai HTTP secara konsisten. REST API biasanya menggunakan request HTTP untuk melakukan operasi seperti membuat, membaca, mengubah, dan menghapus data. |
| 18 | |
| 19 | REST bukan protokol resmi yang kaku. Lebih tepatnya, REST adalah sekumpulan prinsip yang membantu API terasa lebih rapi, mudah dipahami, dan lebih mudah dipelihara. |
| 20 | |
| 21 | ## Prinsip-prinsip REST |
| 22 | |
| 23 | ### 1. Client-Server Architecture |
| 24 | Client dan server terpisah, memungkinkan keduanya berkembang secara independen. |
| 25 | |
| 26 | ### 2. Stateless |
| 27 | Setiap request dari client ke server harus mengandung semua informasi yang diperlukan. Server tidak menyimpan state client. |
| 28 | |
| 29 | ### 3. Cacheable |
| 30 | Response harus mendefinisikan apakah data bisa di-cache untuk meningkatkan performa. |
| 31 | |
| 32 | ### 4. Uniform Interface |
| 33 | Interface yang konsisten antara client dan server, termasuk: |
| 34 | - Resource identification via URI |
| 35 | - Manipulation melalui representations |
| 36 | - Self-descriptive messages |
| 37 | - HATEOAS (Hypermedia as the Engine of Application State) |
| 38 | |
| 39 | ### 5. Layered System |
| 40 | Architecture bisa tersusun dari multiple layers (security, load balancing, caching). |
| 41 | |
| 42 | ### 6. Code on Demand (Optional) |
| 43 | Server bisa mengirim executable code ke client (misalnya JavaScript). |
| 44 | |
| 45 | ## HTTP Methods dalam REST |
| 46 | |
| 47 | REST menggunakan HTTP methods standar untuk operasi: |
| 48 | |
| 49 | ### GET - Membaca Data |
| 50 | ```javascript |
| 51 | // Mendapatkan semua users |
| 52 | GET /api/users |
| 53 | |
| 54 | // Mendapatkan user spesifik |
| 55 | GET /api/users/123 |
| 56 | ``` |
| 57 | |
| 58 | ### POST - Membuat Data Baru |
| 59 | ```javascript |
| 60 | POST /api/users |
| 61 | Content-Type: application/json |
| 62 | |
| 63 | { |
| 64 | "name": "Budi Santoso", |
| 65 | "email": "budi@example.com" |
| 66 | } |
| 67 | ``` |
| 68 | |
| 69 | ### PUT - Update Data (Replace) |
| 70 | ```javascript |
| 71 | PUT /api/users/123 |
| 72 | Content-Type: application/json |
| 73 | |
| 74 | { |
| 75 | "name": "Budi Santoso Updated", |
| 76 | "email": "budi.new@example.com" |
| 77 | } |
| 78 | ``` |
| 79 | |
| 80 | ### PATCH - Update Data Sebagian |
| 81 | ```javascript |
| 82 | PATCH /api/users/123 |
| 83 | Content-Type: application/json |
| 84 | |
| 85 | { |
| 86 | "email": "budi.new@example.com" |
| 87 | } |
| 88 | ``` |
| 89 | |
| 90 | ### DELETE - Hapus Data |
| 91 | ```javascript |
| 92 | DELETE /api/users/123 |
| 93 | ``` |
| 94 | |
| 95 | ## HTTP Status Codes |
| 96 | |
| 97 | REST API menggunakan HTTP status codes untuk mengindikasikan hasil request: |
| 98 | |
| 99 | ### 2xx - Success |
| 100 | - `200 OK` - Request berhasil |
| 101 | - `201 Created` - Resource baru berhasil dibuat |
| 102 | - `204 No Content` - Request berhasil, tidak ada content yang dikembalikan |
| 103 | |
| 104 | ### 3xx - Redirection |
| 105 | - `301 Moved Permanently` - Resource dipindah permanent |
| 106 | - `304 Not Modified` - Resource tidak berubah (cache masih valid) |
| 107 | |
| 108 | ### 4xx - Client Errors |
| 109 | - `400 Bad Request` - Request tidak valid |
| 110 | - `401 Unauthorized` - Authentication required |
| 111 | - `403 Forbidden` - Authenticated tapi tidak ada permission |
| 112 | - `404 Not Found` - Resource tidak ditemukan |
| 113 | - `422 Unprocessable Entity` - Validation error |
| 114 | |
| 115 | ### 5xx - Server Errors |
| 116 | - `500 Internal Server Error` - Error di server |
| 117 | - `502 Bad Gateway` - Invalid response dari upstream server |
| 118 | - `503 Service Unavailable` - Server temporary down |
| 119 | |
| 120 | ## Contoh REST API Lengkap |
| 121 | |
| 122 | ### Resource: Products |
| 123 | |
| 124 | ```javascript |
| 125 | // GET /api/products - List semua products |
| 126 | Response: 200 OK |
| 127 | [ |
| 128 | { |
| 129 | "id": 1, |
| 130 | "name": "Laptop ASUS", |
| 131 | "price": 8500000, |
| 132 | "stock": 15 |
| 133 | }, |
| 134 | { |
| 135 | "id": 2, |
| 136 | "name": "Mouse Logitech", |
| 137 | "price": 250000, |
| 138 | "stock": 50 |
| 139 | } |
| 140 | ] |
| 141 | |
| 142 | // GET /api/products/1 - Detail product |
| 143 | Response: 200 OK |
| 144 | { |
| 145 | "id": 1, |
| 146 | "name": "Laptop ASUS", |
| 147 | "price": 8500000, |
| 148 | "stock": 15, |
| 149 | "description": "Laptop gaming dengan spesifikasi tinggi", |
| 150 | "created_at": "2024-01-01T10:00:00Z" |
| 151 | } |
| 152 | |
| 153 | // POST /api/products - Create product baru |
| 154 | Request Body: |
| 155 | { |
| 156 | "name": "Keyboard Mechanical", |
| 157 | "price": 750000, |
| 158 | "stock": 30 |
| 159 | } |
| 160 | |
| 161 | Response: 201 Created |
| 162 | { |
| 163 | "id": 3, |
| 164 | "name": "Keyboard Mechanical", |
| 165 | "price": 750000, |
| 166 | "stock": 30, |
| 167 | "created_at": "2024-01-15T14:30:00Z" |
| 168 | } |
| 169 | |
| 170 | // PUT /api/products/1 - Update product |
| 171 | Request Body: |
| 172 | { |
| 173 | "name": "Laptop ASUS ROG", |
| 174 | "price": 9000000, |
| 175 | "stock": 12 |
| 176 | } |
| 177 | |
| 178 | Response: 200 OK |
| 179 | { |
| 180 | "id": 1, |
| 181 | "name": "Laptop ASUS ROG", |
| 182 | "price": 9000000, |
| 183 | "stock": 12, |
| 184 | "updated_at": "2024-01-15T15:00:00Z" |
| 185 | } |
| 186 | |
| 187 | // DELETE /api/products/1 - Hapus product |
| 188 | Response: 204 No Content |
| 189 | ``` |
| 190 | |
| 191 | ## Best Practices REST API |
| 192 | |
| 193 | ### 1. Gunakan Nouns, Bukan Verbs |
| 194 | **Kurang tepat:** |
| 195 | ``` |
| 196 | GET /getUsers |
| 197 | POST /createUser |
| 198 | PUT /updateUser |
| 199 | DELETE /deleteUser |
| 200 | ``` |
| 201 | |
| 202 | **Lebih baik:** |
| 203 | ``` |
| 204 | GET /users |
| 205 | POST /users |
| 206 | PUT /users/123 |
| 207 | DELETE /users/123 |
| 208 | ``` |
| 209 | |
| 210 | ### 2. Gunakan Plural untuk Collection |
| 211 | **Lebih baik:** |
| 212 | ``` |
| 213 | GET /users |
| 214 | GET /products |
| 215 | GET /orders |
| 216 | ``` |
| 217 | |
| 218 | ### 3. Nested Resources untuk Relationships |
| 219 | ```javascript |
| 220 | // Orders milik user tertentu |
| 221 | GET /users/123/orders |
| 222 | |
| 223 | // Comments milik post tertentu |
| 224 | GET /posts/456/comments |
| 225 | |
| 226 | // Specific comment |
| 227 | GET /posts/456/comments/789 |
| 228 | ``` |
| 229 | |
| 230 | ### 4. Filtering, Sorting, dan Pagination |
| 231 | ```javascript |
| 232 | // Filtering |
| 233 | GET /products?category=laptop&price_min=5000000 |
| 234 | |
| 235 | // Sorting |
| 236 | GET /products?sort=price&order=desc |
| 237 | |
| 238 | // Pagination |
| 239 | GET /products?page=2&limit=20 |
| 240 | |
| 241 | // Kombinasi |
| 242 | GET /products?category=laptop&sort=price&order=asc&page=1&limit=10 |
| 243 | ``` |
| 244 | |
| 245 | ### 5. Versioning |
| 246 | ```javascript |
| 247 | // URL versioning (paling umum) |
| 248 | GET /api/v1/users |
| 249 | GET /api/v2/users |
| 250 | |
| 251 | // Header versioning |
| 252 | GET /api/users |
| 253 | Headers: Accept: application/vnd.api.v1+json |
| 254 | |
| 255 | // Query parameter |
| 256 | GET /api/users?version=1 |
| 257 | ``` |
| 258 | |
| 259 | ### 6. Consistent Error Responses |
| 260 | ```javascript |
| 261 | { |
| 262 | "error": { |
| 263 | "code": "VALIDATION_ERROR", |
| 264 | "message": "Data yang dikirim tidak valid", |
| 265 | "details": [ |
| 266 | { |
| 267 | "field": "email", |
| 268 | "message": "Email format tidak valid" |
| 269 | }, |
| 270 | { |
| 271 | "field": "password", |
| 272 | "message": "Password minimal 8 karakter" |
| 273 | } |
| 274 | ] |
| 275 | } |
| 276 | } |
| 277 | ``` |
| 278 | |
| 279 | ## Implementasi REST API |
| 280 | |
| 281 | ### Node.js dengan Express |
| 282 | ```javascript |
| 283 | const express = require('express'); |
| 284 | const app = express(); |
| 285 | |
| 286 | app.use(express.json()); |
| 287 | |
| 288 | // GET all users |
| 289 | app.get('/api/users', async (req, res) => { |
| 290 | const users = await db.users.findAll(); |
| 291 | res.json(users); |
| 292 | }); |
| 293 | |
| 294 | // GET user by ID |
| 295 | app.get('/api/users/:id', async (req, res) => { |
| 296 | const user = await db.users.findById(req.params.id); |
| 297 | if (!user) { |
| 298 | return res.status(404).json({ error: 'User not found' }); |
| 299 | } |
| 300 | res.json(user); |
| 301 | }); |
| 302 | |
| 303 | // POST create user |
| 304 | app.post('/api/users', async (req, res) => { |
| 305 | const { name, email } = req.body; |
| 306 | const user = await db.users.create({ name, email }); |
| 307 | res.status(201).json(user); |
| 308 | }); |
| 309 | |
| 310 | // PUT update user |
| 311 | app.put('/api/users/:id', async (req, res) => { |
| 312 | const user = await db.users.update(req.params.id, req.body); |
| 313 | res.json(user); |
| 314 | }); |
| 315 | |
| 316 | // DELETE user |
| 317 | app.delete('/api/users/:id', async (req, res) => { |
| 318 | await db.users.delete(req.params.id); |
| 319 | res.status(204).send(); |
| 320 | }); |
| 321 | |
| 322 | app.listen(3000); |
| 323 | ``` |
| 324 | |
| 325 | ### Ruby on Rails |
| 326 | ```ruby |
| 327 | class Api::UsersController < ApplicationController |
| 328 | # GET /api/users |
| 329 | def index |
| 330 | @users = User.all |
| 331 | render json: @users |
| 332 | end |
| 333 | |
| 334 | # GET /api/users/:id |
| 335 | def show |
| 336 | @user = User.find(params[:id]) |
| 337 | render json: @user |
| 338 | end |
| 339 | |
| 340 | # POST /api/users |
| 341 | def create |
| 342 | @user = User.new(user_params) |
| 343 | if @user.save |
| 344 | render json: @user, status: :created |
| 345 | else |
| 346 | render json: @user.errors, status: :unprocessable_entity |
| 347 | end |
| 348 | end |
| 349 | |
| 350 | # PUT /api/users/:id |
| 351 | def update |
| 352 | @user = User.find(params[:id]) |
| 353 | if @user.update(user_params) |
| 354 | render json: @user |
| 355 | else |
| 356 | render json: @user.errors, status: :unprocessable_entity |
| 357 | end |
| 358 | end |
| 359 | |
| 360 | # DELETE /api/users/:id |
| 361 | def destroy |
| 362 | @user = User.find(params[:id]) |
| 363 | @user.destroy |
| 364 | head :no_content |
| 365 | end |
| 366 | |
| 367 | private |
| 368 | |
| 369 | def user_params |
| 370 | params.require(:user).permit(:name, :email) |
| 371 | end |
| 372 | end |
| 373 | ``` |
| 374 | |
| 375 | ## Authentication di REST API |
| 376 | |
| 377 | ### 1. API Keys |
| 378 | ```javascript |
| 379 | GET /api/users |
| 380 | Headers: |
| 381 | X-API-Key: your_api_key_here |
| 382 | ``` |
| 383 | |
| 384 | ### 2. Bearer Token (JWT) |
| 385 | ```javascript |
| 386 | POST /api/login |
| 387 | { |
| 388 | "email": "user@example.com", |
| 389 | "password": "password123" |
| 390 | } |
| 391 | |
| 392 | Response: |
| 393 | { |
| 394 | "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." |
| 395 | } |
| 396 | |
| 397 | // Subsequent requests |
| 398 | GET /api/users |
| 399 | Headers: |
| 400 | Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
| 401 | ``` |
| 402 | |
| 403 | ### 3. OAuth 2.0 |
| 404 | Untuk third-party authentication (Google, Facebook, GitHub). |
| 405 | |
| 406 | ## REST vs GraphQL |
| 407 | |
| 408 | | Aspek | REST | GraphQL | |
| 409 | |-------|------|---------| |
| 410 | | **Endpoints** | Banyak endpoint | Satu endpoint | |
| 411 | | **Data Fetching** | Over-fetching atau under-fetching bisa terjadi | Client bisa memilih data yang dibutuhkan | |
| 412 | | **Learning Curve** | Lebih mudah dipelajari | Lebih kompleks | |
| 413 | | **Caching** | Dukungan HTTP caching lebih langsung | Biasanya perlu pendekatan khusus | |
| 414 | | **Maturity** | Sudah lama dipakai luas | Relatif lebih baru dan masih berkembang | |
| 415 | |
| 416 | ## Tools untuk Testing REST API |
| 417 | |
| 418 | ### 1. Postman |
| 419 | GUI tool yang sering dipakai untuk testing API. |
| 420 | |
| 421 | ### 2. cURL |
| 422 | Command line tool untuk HTTP requests. |
| 423 | ```bash |
| 424 | curl -X GET https://api.example.com/users |
| 425 | curl -X POST https://api.example.com/users \ |
| 426 | -H "Content-Type: application/json" \ |
| 427 | -d '{"name":"Budi","email":"budi@example.com"}' |
| 428 | ``` |
| 429 | |
| 430 | ### 3. HTTPie |
| 431 | User-friendly command line HTTP client. |
| 432 | ```bash |
| 433 | http GET https://api.example.com/users |
| 434 | http POST https://api.example.com/users name=Budi email=budi@example.com |
| 435 | ``` |
| 436 | |
| 437 | ### 4. Insomnia |
| 438 | Alternative GUI tool seperti Postman. |
| 439 | |
| 440 | ## Kesalahan Umum dalam REST API |
| 441 | |
| 442 | 1. **Menggunakan Verbs di URL** - `/getUser` instead of `/users` |
| 443 | 2. **Tidak Consistent dengan Status Codes** - Return 200 untuk semua response |
| 444 | 3. **Tidak Handle Errors dengan Baik** - Error message tidak jelas |
| 445 | 4. **Exposing Internal Structure** - URL mencerminkan database structure |
| 446 | 5. **Tidak Implement Rate Limiting** - API bisa di-abuse |
| 447 | 6. **Tidak Versioning** - Breaking changes tanpa backward compatibility |
| 448 | |
| 449 | ## Tips untuk Developer |
| 450 | |
| 451 | 1. **Design First** - Plan API structure sebelum coding |
| 452 | 2. **Document Everything** - Gunakan Swagger/OpenAPI untuk dokumentasi |
| 453 | 3. **Test Thoroughly** - Write integration tests untuk API endpoints |
| 454 | 4. **Monitor Performance** - Track response times dan error rates |
| 455 | 5. **Security First** - Always validate input, use HTTPS, implement authentication |
| 456 | 6. **Follow Standards** - Gunakan HTTP methods dan status codes dengan benar |
| 457 | |
| 458 | ## Kesimpulan |
| 459 | |
| 460 | REST masih menjadi pendekatan yang sangat umum untuk membangun API, terutama di aplikasi web. Dengan memahami prinsip dasarnya, Anda bisa merancang endpoint yang lebih jelas, response yang lebih konsisten, dan integrasi yang lebih mudah dipakai tim lain. |
| 461 | |
| 462 | Kalau Anda sedang belajar backend, REST adalah tempat yang bagus untuk mulai. Coba bangun API sederhana dulu, pahami penggunaan HTTP methods dan status code, lalu pelan-pelan tambah fitur seperti autentikasi, pagination, filtering, dan versioning. |