Memahami apa itu RESTful API dan Implementasinya

Dipublikasikan 1 bulan yang lalu 30 min read

Halo cuy ! Karena gue rasa penting mempelajari apa itu RESTful API dalam dunia coding, jadi gue mutusin buat lebih serius memahaminya, walaupun sistem yang biasa gue bangun kebanyakan masih monolit, baik ngoding santai maupun kerjaan kantor.  Dikantor gue juga gue sempet berkolaborasi dan megang bagian yang berurusan dengan API walaupun gue cuman "nembak" endpoint gak bikin API-nya sendiri, itu cukup bikin gue penasaran untuk mempelajarinya. OKE LANGSUNG AJA !

Secara fungsi API membantu pengembang membuat aplikasi lebih cepat dan efisien dengan memanfaatkan fitur atau layanan yang sudah tersedia dari aplikasi lain, misalnya melalui API publik. Dengan API, pengembang tidak perlu membangun semua fitur dari nol karena aplikasi dapat terhubung dengan sistem eksternal seperti pembayaran, peta, atau data cuaca. Selain mempercepat proses pengembangan, API juga memudahkan integrasi antar aplikasi karena layanan dapat dibuat secara modular dan digunakan oleh berbagai sistem yang berbeda. Biasanya API diimplementasikan melalui Web Service agar dapat terhubung dan digunakan oleh Aplikasi atau Client berbeda.

Lalu pertanyaannya apa itu RESTful API?. Sebelumya memahami apa itu, penting untuk mengetahui terlebih dahulu apa itu API,Interface dan REST API pada sistem/komputer, jadi apa itu ?  

Lalu apa itu RESTful API? sebelum masuk ada lagi hal penting yang harus dipahami, yaitu cara kerja HTTP. karena REST API hampir selalu menggunakan HTTP, yang perlu dipahami disini REST API != HTTP, karena REST API itu gaya arsitektur bukan protokol, dan REST API tidak terikat dengan protokol HTTP.

Gue sendiri juga belum terlalu dalem mempelajari implementasi REST di luar HTTP karena di dunia nyata hampir semuanya pakai HTTP, jadi ya lebih baik fokus ke HTTP saja.

Cara kerja HTTP

Contoh penggunaan HTTP saat kita mengetikan alamat website seperti facebook.com atau instagram.com browser melakukan Request yang secara default browser menggunakan Method GET, dan server menerima Request tersebut dan mengembalikan Response yang pada umumnya berupa HTML ke client. Contoh kasus ketika mengakses halaman utama yaitu personal-blog.test/

Disisi Server Request diterima dan Mengembalikan dalam bentuk HTML/ Halaman Home.

   Route::prefix('categories')->name('categories.')->group(function () {
            Route::get('/', [CategoryController::class, 'index'])
                ->name('index');
        });

Contoh lainnnya didalam Form HTML ketika kita melakukan submit, disini terjadi Reqest Response HTTP, biasanya menggunakan Method POST, dan juga mengirimkan data yang disisipkan di body Reqeuest.  Contoh kasus ketika melakukan Submit Form Edit Categories pada Blog. 

    Route::prefix('categories')->name('categories.')->group(function () {
            Route::put('/{category}', [CategoryController::class, 'update'])
                ->name('update');
        });

Ada hal unik yang terjadi terkait method pada browser, Melalui Browser Navigation URL dan Form HTML native hanya mendukung method GET dan POST. dengan menggunakan fetch/ajax Javascript kita baru bisa menggunakan Method PUT, PATCH dll.  Lalu kenapa pada menu Category tersebut terdapat Method PUT dll? itu karena Framework seperti CI/Laravel mengatasinya dengan menyisipkan input method pada Form sehingga kita dapat melakuan Request Selain GET dan POST, walaupun sebenarnya disisi browser tetap menggunakan Method POST hanya saja Framework yang menginterpresentasikannya sebagai method PUT.  bisa dilihat gambar dibawah terdapat input hidden dengan name="_method" dan  value ="PUT"

Jadi disini bisa dilihat dengan jelas Cara kerja HTTP, yaitu Client melakukan Request dengan Method GET/POST dan Server Mengembalikan data berupa HTML atau Lainnya. 

Lalu untuk apa menggunakan API jika menggunakan Sistem Monolit seperti ini sudah bisa berjalan? oke sabar... kita masuk ke Ilustrasi REST API terlebih dahulu :).

Ilustrasi REST API

Rest API sering kali diilustrasikan sebagai Kegiatan yang ada di restoran, kita sebagai customer bisa di anggap (sebagai client/requester), yang pesanannya atau (Requestnya) akan di terima oleh pelayan yang bisa dianggap (sebagai API) "perantara" yang kemudian akan di proses oleh dapur (Server), yang jika dapur sudah menyelesaikan pesananya maka akan memberikan Pesanan Makanan ke Pelayan, yang nanti akan diterima Customer sebagai Response berupa makanan. 

Dari ilustrasi tersebut terlihat biasa bukan? lalu apa bedanya dengan request website tradisional?  Perbedaan utama website tradisional dan REST API terletak pada bentuk response yang diberikan server. Pada website tradisional, server biasanya mengirimkan HTML yang siap ditampilkan browser. Sedangkan pada REST API, server umumnya hanya mengirimkan data mentah seperti JSON yang nantinya diolah lagi oleh client atau frontend. 

REST API adalah aturan komunikasi antara client dan server yang membuat request dan response memiliki struktur yang jelas. Dalam analogi restoran, REST API bisa diibaratkan seperti menu restoran yang menentukan apa saja yang bisa dipesan oleh customer. Customer tidak bisa meminta sesuatu di luar menu yang tersedia, sama seperti client tidak bisa melakukan request ke endpoint yang tidak disediakan server. Setiap menu juga memiliki aturan yang jelas, misalnya cara pemesanan dan hasil yang akan diberikan, seperti endpoint API yang memiliki URL, method, dan format response tertentu.

Jadi REST API itu jelas adalah aturan, lalu apa bedanya REST API vs RESTful API ?

jika dianalaogin dalam restoran itu seperti ini

jadi terlihat bedanya? aturan disini mengacu pada prinsip REST contohnya 

Pada RESTful API itu tidak ada standarisasi teknisnya, tetapi API dapat dikatakan RESTful jika berusaha mengacu pada prinsip-prinsip REST yang dijelaskan oleh Roy Fielding dalam disertasi doktoralnya pada tahun 2000 yang berjudul Architectural Styles and the Design of Network-based Software Architectures.

Contoh  tidak RESTful API.

(ini bukan REST API murni ini sistem di blog ini buat analogi aja)

Ketika kita melakukan Request untuk update Category dengan method PUT.  setelah submit kita diarahkan ke halaman index Category atau list Category.

Dari sisi server melakukan proses Update pada categories yang dipilih, dengan contoh Laravel Endpoint dan Route seperti ini. PUT /categories/1

    Route::prefix('categories')->name('categories.')->group(function () {
            Route::put('/{category}', [CategoryController::class, 'update'])
                ->name('update');
        });

Disini endpoint sebenarnya sudah mengikuti prinsip REST seperti penggunaan method PUT dan URI berbasis resource (/categories/{category}), namun implementasinya masih lebih berorientasi ke web application karena response yang dikembalikan masih berupa HTML/view, bukan data JSON seperti REST API modern pada umumnya.

Jadi sudah nangkep kan apa itu RESTful API ? oke itu adalah pemahaman yang harus dipahami terkair RESTful API, untuk tahap selanjutnya kita bedah terkait implementasi RESTful API dari aspek HTTP.

Aspek HTTP pada RESTful API

kenapa HTTP?

Seperti yang dijelaskan sebelumnya  RESTful API itu arsitektural style, bukan protokol, jadi tidak ada keharusan menggunakan HTTP secara mutlak, dan kenapa lebih sering HTTP kenapa tidak pakai protokol lain ? 

HTTP Header

HTTP Header adalah informasi tambahan  yang bisa dikirim oleh client atau server, Informasi metadata atau informasi teknis yang bukan bagian utama dari resource/data biasanya lebih cocok dikirim melalui HTTP Header. Dan HTTP Header itu bisa ditulis diluar standar sesuai dengan kebutuhan, tapi tetap direkomendasikan menggunakan HTTP Header yang sudah ada (standar), HTTP header itu bentuknya Key dan Value. Contoh nya ketika ada Aplikasi Mobile, dan untuk mengirimkan Versi Aplikasi Mobile itu sebaiknya jangan gunakan Body atau Query Parameter tapi gunakan HTTP Header karena itu tidak ada kaitannya dengan resource/data.

Accept

Accept header pada HTTP digunakan client untuk memberi tahu server. Dalam RESTful API, biasanya client meminta data dalam bentuk JSON. Contoh.

Request Accept: application/json

Response Content-Type: application/json

Content Type

Content type bergantung pada server, jadi jika Request Accept: text/html belum tentu Responsenya Content-Type: text/html bisa saja Content-Type: application/json yang diterima.

Accept-Language

Accept-Language: en-US
Accept-Language: id-ID

User-Agent, Referer, dan Lain - Lain. (masih banyak header lainnya)

HTTP Response Code

Berikut Groping Response Code berdasarkan Kepalanya.

Response Code Arti
1xx Informasi bahwa request sedang diproses
2xx Request berhasil diproses
3xx Redirect atau perpindahan resource
4xx Kesalahan pada request dari client
5xx Kesalahan pada server

Pada RESTful API, HTTP Response Code yang paling sering digunakan biasanya adalah 2xx, 4xx, dan 5xx. Pada RESTful API Selau gunakan Status Code yang standar misalnya ketika Create Data pastikan API mengembalikan 201 Created untuk Response Codenya. Dan Ketika Update Data Pastikan Response Codenya 204 No Content

Pada RESTful API, selalu gunakan HTTP Status Code standar sesuai kondisi response. Contoh :

{
  "message": "User updated"
}

Sesuaikan status code dengan isi response dan kondisi request.

HTTP Method

HTTP Method adalah metode permintaan dari client, untuk menunjukkan tindakan yang diinginkan yang akan dilakukan ke server. Method pada HTTP ada banyak, tapi hanya ada beberapa saja yang umum atau sering digunakan, sebagai berikut :

HTTP Method Keterangan
GET Meminta data dari server
POST Mengirim data ke server
PUT Mengubah seluruh data yang sudah ada di server
PATCH Mengubah sebagian data yang sudah ada di server
DELETE Menghapus data yang sudah ada di server

Jika ditransform ke Method terkait kesesuaian dengan Prinsip RESTful API maka seperti ini.

HTTP Method Keterangan
GET Mengambil atau mencari record di server
POST Membuat record baru di server
PUT Mengubah seluruh atribut record yang sudah ada di server
PATCH Mengubah sebagian atribut record yang sudah ada di server
DELETE Menghapus record di server

URL (Uniform Resource Locator)

URL adalah alamat yang digunakan di web untuk mengakases sebuah resource, disini harus diperhatikan untuk membuat RESTful API URL juga harus dibuat dengan baik. Struktur URL.

HTTP Message

HTTP Message adalah bagaimana data bertukar dari client dan server, Ada 2 tipe message :

HTTP Message memiliki format standard seperti berikut ini :

Authentication dan Authorization

Pada RESTful API pada umumnya terdapat mekanisme Authentication dan Authorization,  ada kalanya kita mengamankan RESTful API dan membatasi pihak mana yang boleh mengakses RESTful API. Untuk detailnya :

Contoh mekanisme Authentication yang umum digunakan pada RESTful API antara lain Basic Authentication, API Key, OAuth 2.0. Setelah proses Authentication berhasil, Authorization digunakan untuk menentukan hak akses yang dimiliki oleh pengguna atau sistem, misalnya melalui Role, Permission, Policy, atau Scope.

Contoh Authentication dan Authorization

Basic Authentication adalah mekanisme Authentication sederhana yang menggunakan username dan password. Kredensial tersebut dikirim melalui header Authorization pada setiap request. Ini jarang digunakan diaplikasi Mobile Apps atau Client. Basic Authentication jarang digunakan pada aplikasi mobile maupun Single Page Application (SPA). Hal ini karena aplikasi harus menyimpan username dan password pengguna atau kredensial aplikasi. Jika terjadi kesalahan implementasi atau kredensial berhasil diekstrak dari aplikasi, pihak lain dapat memperoleh akses menggunakan kredensial tersebut.

Oleh karena itu, aplikasi modern umumnya lebih memilih menggunakan OAuth 2.0 karena kredensial utama tidak perlu dikirim pada setiap request dan akses dapat dibatasi melalui masa berlaku token maupun hak akses tertentu.

Contoh : Authorization: Basic base64(username:password)

Authentication sederhana yang menggunakan API Key atau Secret Key sebagai identitas aplikasi yang mengakses API. API Key dikirim melalui header request dan akan diverifikasi oleh server sebelum akses diberikan. Umumnya digunakan pada komunikasi Server-to-Server, integrasi antar aplikasi, atau API internal. Implementasinya sederhana, namun jika API Key bocor maka pihak lain dapat mengakses API hingga key tersebut dicabut atau digenerate ulang.

Contoh: API-Key: random-api-key-urnod2i3unr8qy78n8nrf83ufior2u3fior

OAuth 2.0 adalah authorization yang memungkinkan sebuah aplikasi memperoleh akses terbatas ke resource milik pengguna tanpa perlu mengetahui username dan password pengguna tersebut. OAuth 2.0 bekerja dengan memberikan Access Token kepada aplikasi setelah pengguna berhasil melakukan autentikasi dan memberikan persetujuan akses.

Contoh penggunaan:

• Login dengan Google
• Login dengan GitHub
• Login dengan Microsoft

Alur sederhananya:

Client meminta login → User melakukan login → Server memberikan Access Token dan Refresh Token → Client menggunakan Access Token untuk mengakses API → Access Token expired → Client mengirim Refresh Token → Server memberikan Access Token baru → Client kembali mengakses API

OAuth 2.0 umumnya digunakan pada aplikasi Client-Server, Mobile Apps, Single Page Application (SPA), serta integrasi antar sistem yang memerlukan akses terbatas terhadap resource pengguna. OAuth 2.0 lebih aman dibanding memberikan username dan password secara langsung karena aplikasi hanya menerima token akses dengan hak akses dan masa berlaku tertentu.

Dari penjelasan tersebut dapat disimpulkan bahwa tidak ada satu mekanisme Authentication dan Authorization yang paling baik untuk semua RESTful API. Pemilihannya bergantung pada kebutuhan, tingkat keamanan, serta arsitektur sistem yang dibangun, baik untuk komunikasi Client-Server maupun Server-to-Server.

Resource Naming

Resource Naming adalah cara memberikan nama pada resource (sumber daya/data) di dalam URI atau endpoint API. Resource dalam RESTful API adalah data yang sifatnya bisa satu atau banyak.  Misal, “customers” adalah kumpulan dari “customer”, dimana “customer” adalah satu data customer.

Resource Naming pada RESTful API praktiknya sebagai berikut: 

Gunakan Kata Benda, Bukan Kata Kerja

Contoh Benar :

Contoh Salah :

Gunakan Hirarki

Gunakan hirarki untuk menggambarkan hubungan antar resource, bukan untuk setiap atribut data.

Contoh Benar :

Contoh Salah :

Contoh kasus lanjutan Merchant-Address 

Dalam mendesign Resouce name tidak selalu sesimpel mendesign 1 objek / entitas, ambil contoh kasus berikut :

Merchant
└── Address

merchants
---------
id
name

addresses
---------
id
merchant_id
address

Dari kasus tersebut jika dibuatkan API yang RESTful maka seperti ini.

Contoh benar  ✅

GET    /merchants/1/addresses
POST   /merchants/1/addresses
GET    /merchants/1/addresses/6
GET    /addresses/6
PUT    /addresses/6
DELETE /addresses/6

Contoh Salah ❌

GET    /merchant-addresses/1
POST   /merchant-addresses/1
GET    /merchant-addresses/6
GET    /address/6
PUT    /update-address/6
DELETE /delete-address/6

// mengakses attribute
GET /addresses/6/city
GET /addresses/6/province
GET /addresses/6/postal-code

Nah disini cara mendesign Nama Resource bisa saja jadi kompleks, pada kasus tersebut terbentuk 2 cara jika mengacu untuk mengakses Address, pertama lewat Nested Resource  /merchants/{id}/addresses atau Global Resource /addresses.

Gunakan hirarki untuk menggambarkan hubungan antar resource, bukan untuk setiap atribut data.

Misalnya

Merchant ← Resource
Address  ← Resource

city         ← atribut
province     ← atribut
postal_code  ← atribut

Karena itu tidak perlu membuat hirarki seperti :

GET /addresses/6/city
GET /addresses/6/province
GET /addresses/6/postal-code

yang benar cukup :

GET /addresses/6

Response : 

{
    "id": 6,
    "merchant_id": 1,
    "address": "Jl. Sudirman",
    "city": "Medan",
    "province": "Sumatera Utara",
    "postal_code": "20111"
}

Selalu gunakan format konsisten pada Naming Resource contoh salah menggunakan Address dan Addresses pada API yang sama, selalu gunakan 1 format saja singular/plural, disini tidak ada kewajiban memkai yang mana harus dipakai, tapi selalu pastikan pakai gunakan format yang konsisten. Seracara umum RESTful API kebanyakan menggunakan format Plural pada implementasinya.

Ketika mendesain hirarki REST, pertanyaan: "Apakah objek ini punya ID sendiri dan bisa diakses sendiri?"

Bisa diterjemahkan menjadi: "Apakah rela membuat endpoint CRUD khusus untuk objek ini?"

Gunakan Action Pada Resource

Tidak semua operasi dapat direpresentasikan dengan baik sebagai CRUD terhadap resource., berkaitan dengan aturan "gunakan kata benda pada resource". Karena tidak semua operasi itu CRUD terhadap resource, berikut beberapa operasi yang bukan CRUD terhadap resource.

Operasi seperti ini lebih merupakan aksi (action) dari pada operasi CRUD pada resource. Selalu terapkan action di bawah resource yang relevan.

Contoh Benar :

Contoh Salah :

Gunakan - dan lowercase

Contoh Benar :

Contoh Salah :

Gunakan CRUD pada HTTP Method

Contoh Benar :

Contoh Salah :

Gunakan Query untuk Filter

Contoh Benar :

Contoh Salah :

Versioning

Saat membuat RESTful API, usahakan untuk tidak merusak kompatibilitas (backward compatibility) ketika melakukan perubahan atau upgrade API.

Versioning sebaiknya hanya digunakan ketika perubahan yang dilakukan memang menyebabkan client lama tidak dapat menggunakan API dengan cara yang sama seperti sebelumnya (breaking change).

Sebisa mungkin hindari kondisi ini, karena biaya (cost) yang ditimbulkan cukup besar. Client yang sudah menggunakan API tersebut harus melakukan perubahan pada aplikasi yang sudah berjalan agar tetap dapat berkomunikasi dengan API versi terbaru. 

Namun jika breaking change memang tidak dapat dihindari, maka kita perlu membuat versi baru dari API tersebut (API Versioning) agar client lama tetap dapat menggunakan versi sebelumnya tanpa terganggu. backward compatibility sangat dijaga dan versioning biasanya menjadi pilihan terakhir.

Ada 2 Cara umum pada Versioning :

Versioning Pada URL

Versioning Menggunakan HTTP Header

RESTful API yang baik semaksimal mungkin tidak merusak API. Sehingga sebenarnya tidak butuh membuat API versi baru.  jadi ketika maintanance itu sebaiknya tidak merusak kompabilitas dan hanya melakukan perbahan yang tidak merusak API seperti menambahakan field, meningkatkan peforma, fix bug, meningkatkan keamanan, menambahkan endpoint baru, dll.

JSON

JSON (JavaScript Object Notation) adalah format pertukaran data yang digunakan untuk mengirim, menerima, dan menyimpan data secara terstruktur. Meskipun berasal dari sintaks object pada JavaScript, JSON dapat digunakan oleh berbagai bahasa pemrograman.

Pada RESTful API, format data yang paling umum digunakan adalah JSON. Meskipun REST tidak mewajibkan penggunaan JSON, format ini sangat direkomendasikan karena ringan, mudah dibaca oleh manusia, dan didukung oleh hampir semua bahasa pemrograman. contoh :

{
    "id": 1,
    "name": "Junaedi",
    "email": "junaedi@example.com",
    "phone": "081234567890",
    "is_active": true
}

Fomat JSON Konsisten

Contoh tidak Baik ❌

Formatnya berubah ubah tiap response.

GET /users/1

{
    "id": 1,
    "name": "Junaedi"
}

GET /products/1

{
    "success": true,
    "data": {
        "id": 1,
        "name": "Laptop"
    }
}

GET /orders/1

{
    "result": {
        "id": 1,
        "total": 500000
    }
}

Contoh Baik  ✅

GET /users/1

{
    "success": false,
    "message": "User tidak ditemukan"
}

GET /products/1

{
    "success": true,
    "data": {
        "id": 1,
        "name": "Laptop"
    }
}

GET /orders/1

{
    "success": true,
    "data": {
        "id": 1,
        "total": 500000
    }
}

JSON API

Saat menentukan standar format JSON, kadang sering terjadi perdebatan antar programmer. JSON API adalah salah satu format standard untuk JSON yang bisa digunakan. Format di JSON API sudah mendukung HATEOAS. https://jsonapi.org/

HATEOAS

HATEOAS singkatan dari Hypermedia as the Engine of Application State. Hypermedia artinya content yang memiliki link menuju resource yang ada.

Biasanya URL API pada RESTful API sudah di hardcode di Client. Dengan menggunakan HATEOAS, client bisa secara dinamis mendapatkan URL lokasi resource dari response data Server.

Contoh ketika GET /accounts/123456789

Tanpa HATEOAS ❌

{
    "account_number": "123456789",
    "owner_name": "Junaedi",
    "balance": 5000000
}

Maka client harus sudah mengetahui endpoint-endpoint tersebut:

/accounts/123456789/transactions
/accounts/123456789/transfers
/accounts/123456789/cards

Dengan HATEOAS✅

{
    "account_number": "123456789",
    "owner_name": "Junaedi",
    "balance": 5000000,
    "_links": {
        "self": {
            "href": "/accounts/123456789"
        },
        "transactions": {
            "href": "/accounts/123456789/transactions"
        },
        "transfer": {
            "href": "/accounts/123456789/transfers"
        },
        "cards": {
            "href": "/accounts/123456789/cards"
        }
    }
}

Client cukup membaca:

{
    "_links": {
        "transactions": {
            "href": "/accounts/123456789/transactions"
        }
    }
}

Contoh kasus menarik ketika rekening diblokir.

{
    "account_number": "123456789",
    "status": "BLOCKED",
    "_links": {
        "self": {
            "href": "/accounts/123456789"
        },
        "unblock": {
            "href": "/accounts/123456789/unblock"
        }
    }
}

Perhatikan transfer,withdraw,payment tidak muncul dari Response saja Client sudah tau, aksi yang tersedia hanya membuka blokir rekening. Di sinilah kata Hypermedia as the Engine of Application State menjadi masuk akal. Links disini tidak ada format standar jadi bisa saja ditulis _links , links, link atau bahkan  resources, navigation.

Caching

Secara sederhana cache adalah data bersifat sementara yang disimpan pada sistem penyimpanan. Dalam RESTful API, data cache biasanya disimpan di client (misal di web browser, atau di mobile app) Fokus Cache pada RESTful API itu Client Cache, yang dikendalikan melalui HTTP Header. Cache biasa digunakan untuk menurunkan jumlah data transfer antara client dan server sehingga proses komunikasi lebih cepat. Cache menyimpan response HTTP yang kemungkinan akan diminta kembali di masa depan, baik response tersebut berupa JSON, gambar, CSS, JavaScript, HTML, maupun jenis data lainnya.

Idempotance

Dalam RESTful API, ketika membuat multiple request yang identik, harus memiliki efek yang sama seperti membuat satu request. Dalam hal ini, maka RESTful API kita bisa dibilang idempotent. Idempotent itu sangat penting, karena saat membuat RESTful API, kita akan melakukan komunikasi antara client dan server via network, sehingga error bisa terjadi. Belum lagi, banyak framework atau library client yang bisa secara otomatis melakukan request ulang ketika terjadi error pada network. Efek yang sama yang dimaksud itu bukan mengacu pada Response tapi impact di sisi servernya. 

Implementasi Idempotent di RESTful API

Secara default HTTP method sudah idempotance, lalu kenapa di prinsip RESTful API di tegaskan ulang? Karena banyak developer membuat implementasi yang secara method terlihat benar tetapi perilakunya tidak idempotent.  jadi konteksnya lebih ke prilakunya implementasi bukan methodnya.

Implementasi GET

Contoh Benar ✅

Jika melakuan GET method 2x GET /articles/10 Response ke-1 dan ke-2 harusnya menjamin GET tersebut tidak mengubah state server.

{
  "id": 10,
  "title": "Memahami RESTful API",
  "views": 101
}

Contoh Salah❌

Contoh yang Sering Terjadi (Tidak Idempotent) . Jika melakuan GET method 2x GET /articles/10. Dan endpoint GET tersebut secara internal melakukan (views = views + 1).

Response ke-1

{
  "id": 10,
  "title": "REST API",
  "views": 101
}

Responseke-2 

{
  "id": 10,
  "title": "REST API",
  "views": 102
}

Disini mungkin terlihat tidak idempotent karena request GET yang identik menghasilkan response yang berbeda, terlihat pada nilai views yang awalnya 101 menjadi 102. Namun permasalahannya sebenarnya bukan pada response yang berbeda tersebut. Response justru sudah benar karena merepresentasikan kondisi resource saat ini. Yang menjadi masalah adalah state pada API server berubah akibat request GET itu sendiri. Dengan kata lain, request yang identik menghasilkan state server yang berbeda, bukan sekadar response yang berbeda. Perubahan state inilah yang melanggar prinsip idempotency.

Kenapa konsep ini dibuat? karena jika ada runtutan dengan kasus seperti ini.

Padahal user hanya membuka artikel sekali tapi views bertambah 2x.  Inilah alasan utama idempotency ada: agar request yang diulang karena retry, timeout, refresh browser, cache validation, crawler, dan lain-lain tidak mengubah hasil akhir sistem secara tidak sengaja. Seharusnya untuk mencatat views itu dilakukan di Request yang berbeda setelah GET dengan POST /articles/10/views.

"Kalau increment view dipisah ke POST, bagaimana kalau GET berhasil tetapi POST gagal? Bukankah view jadi tidak tercatat?"

Ini memang trade-off yang sering muncul pada sistem artikel, blog, berita, dan media online. Tetapi alasan banyak sistem tetap memisahkan konsidi tersebut dari GET adalah karena mereka lebih mementingkan Konsistensi HTTP Semantics

daripada akurasi view 100%, karena view sebenarnya hanyalah statistik. Kalau hilang 1-2 view: Walaupun dari sisi bisnis mungkin lebih praktis jika disatukan, karena statistik dianggap "best effort". Bahkan banyak website besar sebenarnya sengaja melanggar prinsip GET yang murni demi kemudahan pencatatan statistik. Itu bukan berarti sistemnya salah, hanya berarti mereka mengorbankan sedikit kemurnian REST untuk kebutuhan bisnis tertentu.

Implementasi POST

Contoh Benar ✅

POST digunakan untuk membuat resource baru atau menjalankan suatu aksi pada server.

Misalnya: POST /orders  Request pertama:

{
  "order_id": 1001,
  "product_id": 10,
  "qty": 1
}

Jika request yang sama dikirim kembali: POST /orders Maka server dapat membuat order baru:

{
  "order_id": 1002,
  "product_id": 10,
  "qty": 1
}

Perilaku ini benar karena POST secara default memang tidak bersifat idempotent. Setiap request dianggap sebagai aksi baru yang harus diproses oleh server.

Kenapa Perlu Diperhatikan? Misalnya terjadi kondisi seperti berikut

Padahal pengguna sebenarnya hanya melakukan satu kali pemesanan. Akibatnya terbentuk dua order yang berbeda:  Order #1001 dan Order #1002.  inilah alasan mengapa POST perlu mendapatkan perhatian khusus ketika terdapat kemungkinan retry akibat timeout, gangguan jaringan, atau kegagalan menerima response.

Cara Mengatasinya

Salah satu solusi yang umum digunakan adalah Idempotency Key. Client mengirim request:

POST /orders  

Idempotency-Key: abc123

{
  "product_id": 10,
  "qty": 1
}

Server menyimpan bahwa key abc123 sudah digunakan untuk membuat Order #1001. Jika client melakukan retry dengan key yang sama:

POST /orders  

Idempotency-Key: abc123

{
  "product_id": 10,
  "qty": 1
}

Server tidak membuat order baru, melainkan mengembalikan hasil dari request sebelumnya. Dengan demikian: Request pertama -> Order #1001 Retry -> Tetap Order #1001

Berbeda dengan GET, PUT, dan DELETE yang secara alami bersifat idempotent, POST tidak menjamin bahwa request yang sama akan menghasilkan state yang sama. Oleh karena itu, endpoint POST yang berhubungan dengan transaksi penting seperti pembuatan order, pembayaran, atau pengiriman data biasanya memerlukan mekanisme tambahan seperti Idempotency Key untuk mencegah duplikasi akibat retry.

Implementasi PUT&PATCH

Contoh Benar ✅

PUT dan PATCH digunakan untuk memperbarui resource yang sudah ada. Misalnya terdapat data user:

{
"id": 1,
"name": "Budi"
}

Kemudian client mengirim request:

PUT /users/1

{
"name": "Andi"
}

Jika request yang sama dikirim kembali:

PUT /users/1

{
"name": "Andi"
}

Maka hasilnya tetap:

{
"id": 1,
"name": "Andi"
}

Walaupun request dieksekusi berkali-kali, state akhir resource tetap sama. Inilah yang membuat PUT bersifat idempotent.

Hal yang sama berlaku untuk PATCH jika digunakan untuk mengubah nilai resource ke kondisi tertentu.

PATCH /users/1

{
"name": "Andi"
}

Request tersebut dapat dikirim berkali-kali dan state akhirnya tetap:

{
"id": 1,
"name": "Andi"
}

Contoh Salah ❌

Kesalahan yang sering terjadi adalah menggunakan PUT atau PATCH untuk melakukan operasi penambahan nilai. Misalnya:

PATCH /articles/10 Implementasi server $article->views++;

Request pertama:

{
"id": 10,
"views": 101
}

Request kedua:

{
"id": 10,
"views": 102
}

Request ketiga:

{
"id": 10,
"views": 103
}

Disini request yang identik menghasilkan state yang berbeda setiap kali dieksekusi. 100 → 101 → 102 → 103

Perilaku seperti ini tidak lagi bersifat idempotent walaupun menggunakan method PUT atau PATCH. Kenapa Perlu Diperhatikan?

Misalnya terjadi kondisi seperti berikut:

Jika PATCH digunakan untuk mengubah nilai menjadi kondisi tertentu: PATCH /articles/10

Maka retry akan menghasilkan: 100 → 101 ,101 → 102 Padahal aksi yang dimaksud pengguna hanya terjadi satu kali.

PUT dan PATCH umumnya bersifat idempotent karena digunakan untuk mengubah resource ke kondisi tertentu. Mengirim request yang sama berkali-kali akan menghasilkan state akhir yang sama. Namun idempotency tidak ditentukan oleh HTTP Method saja, melainkan juga oleh implementasinya. Jika PUT atau PATCH digunakan untuk operasi seperti penambahan counter, penambahan saldo, atau increment nilai tertentu, maka request yang identik dapat menghasilkan state yang berbeda dan tidak lagi bersifat idempotent.

Implementasi DELETE

Contoh Benar ✅

DELETE digunakan untuk menghapus resource yang sudah ada. Misalnya terdapat data user:

{
"id": 1,
"name": "Budi"
}

Kemudian client mengirim request: DELETE /users/1

Request pertama:

{
"message": "User berhasil dihapus"
}

Data user sekarang sudah tidak ada. Jika request yang sama dikirim kembali:

DELETE /users/1

Maka server dapat memberikan response seperti:

{
"message": "User tidak ditemukan"
}

atau

{
"message": "User sudah dihapus"
}

Walaupun response dapat berbeda, state akhir server tetap sama yaitu user tersebut tidak ada lagi. Inilah yang membuat DELETE bersifat idempotent.

Contoh Salah ❌

Kesalahan yang sering terjadi adalah menambahkan efek samping setiap kali DELETE dipanggil.

Misalnya: DELETE /users/1 Implementasi server: $totalDeleted++ Request pertama:

{
"message": "User berhasil dihapus"
}

Jika request yang sama dikirim kembali: State server: totalDeleted = 2

Lallu jika dikirim kembali ke-3 State server: totalDeleted = 3

Disini request yang identik menghasilkan state yang berbeda setiap kali dieksekusi, 0 → 1 → 2 → 3 Walaupun resource yang dihapus sudah tidak ada, request DELETE tetap memberikan efek samping baru pada server sehingga tidak lagi bersifat idempotent.

Kenapa Perlu Diperhatikan?

Misalnya terjadi kondisi seperti berikut:

Jika DELETE diimplementasikan dengan benar:

State akhir server tetap sama sehingga retry aman dilakukan. Namun jika setiap DELETE juga melakukan proses tambahan seperti:

Maka retry dapat menghasilkan efek samping yang tidak diinginkan walaupun resource sebenarnya sudah terhapus pada request pertama.

DELETE secara alami bersifat idempotent karena tujuan utamanya adalah memastikan suatu resource tidak ada lagi. Mengirim request DELETE yang sama berkali-kali akan menghasilkan state akhir yang sama, yaitu resource tetap terhapus. Namun idempotency tidak hanya ditentukan oleh HTTP Method yang digunakan, melainkan juga oleh implementasinya. Jika DELETE menimbulkan efek samping tambahan setiap kali dieksekusi, maka request yang identik dapat menghasilkan state yang berbeda dan tidak lagi bersifat idempotent.

Stateless

Stateless adalah prinsip RESTful API dimana server tidak menyimpan state atau informasi session yang berkaitan dengan client. Setiap request harus bersifat independen dan membawa seluruh informasi yang dibutuhkan server untuk memprosesnya, sehingga server tidak perlu mengetahui atau mengingat request sebelumnya. Dengan pendekatan ini, client bertanggung jawab mengelola state-nya sendiri, sementara server hanya memproses request berdasarkan data yang diterima pada saat itu.

Keuntungan Stateless RESTful API

RESTful API Documentation

RESTful API tidak memiliki spesifikasi resmi dan ketat seperti SOAP. Karena REST merupakan gaya arsitektur, implementasinya dapat berbeda-beda pada setiap API. Oleh karena itu, untuk memudahkan client dalam memahami dan menggunakan RESTful API yang kita buat, sebaiknya disediakan dokumentasi yang jelas. Dokumentasi dapat dibuat dalam berbagai bentuk, mulai dari dokumen sederhana seperti Microsoft Word atau Google Docs hingga menggunakan tool khusus dokumentasi API.

Untuk API yang digunakan oleh banyak developer, penggunaan tool khusus seperti Swagger/OpenAPI umumnya lebih disarankan karena dapat mendokumentasikan endpoint, parameter, request, response, dan contoh penggunaan secara lebih terstruktur.

Membuat RESTful API

Kesalahan Membuat RESTful API ❌

Tahapan Membuat RESTful API ✅

Contoh : 

1.Business Flow

Barang Masuk
      ↓
Stok Bertambah
      ↓
Barang Keluar
      ↓
Stok Berkurang
      ↓
User Melihat Stok Saat Ini

2. UI/UX Screen

3. API Documentation

Melihat daftar barang GET /api/items

[
    {
        "id": 1,
        "name": "Mouse",
        "stock": 25
    },
    {
        "id": 2,
        "name": "Keyboard",
        "stock": 10
    }
]

Detail barang GET /api/items/1

{
    "id": 1,
    "name": "Mouse",
    "stock": 25
}

 Barang masuk POST /api/items/1/inbound

{
    "qty": 10
}

Response :

{
    "message": "Stock updated",
    "stock": 35
}

 Barang keluar POST /api/items/1/outbound

{
    "qty": 5
}

Response :

{
    "message": "Stock updated",
    "stock": 30
}

4. Develop RESTful API

Implementasikan endpoint sesuai dokumentasi.

Route
GET    /api/items
GET    /api/items/{id}
POST   /api/items/{id}/inbound
POST   /api/items/{id}/outbound

Maintenance RESTful API

Dalam membuat produk, fitur pasti akan selalu bertambah, Tak jarang kita mungkin melakukan perubahan di screen Web atau Mobile yang sama. Oleh karena itu, maintenance RESTful API sangatlah penting, agar RESTful API kita tidak menjadi masalah di kemudian hari.

Maintenance : yang Boleh Dilakukan ✅

Maintenance : yang tidak Boleh Dilakukan ❌

Maintanance itu simple, jangan break existing API yang sudah di publish.

Implementasi RESTful API menggunakan Laravel.

Padas implementasi kali ini studi kasus yang digunakan adalah RESTful API To do list. alasannya simple tidak terlalu kompleks dan dapat diimplementasikan dengan Full Resource API / CRUD API. 

Sebelumnya gue sendiri udah buat, lebih tepat nya copy project dari PZN untuk contoh pengaplikasiannya di  Github - Laravel 13 Management Contact RESTful API. Tapi buat memastikan lagi pemahaman lebih matang terkait RESTful API ini jadi gue implementasikan di kasus lain yaitu RESTful API To do list.  Seperti sebelumnya implementasi dibagi menajdi 4 bagian.

1. Bisnis Flow

DESKRIPSI
Aplikasi untuk mencatat dan mengelola daftar pekerjaan (todo) dengan autentikasi. Setiap user hanya dapat mengelola todo miliknya sendiri.

AKTOR
- User : Registrasi, login, kelola todo pribadi

ATURAN BISNIS
- Judul todo wajib diisi
- Deskripsi opsional
- Status awal todo: Belum Selesai
- Todo hanya bisa diakses oleh pemiliknya
- User harus login untuk akses todo
- Login via username ATAU email

FLOW

REGISTER: User 
- Isi Form (nama, username, email, password)
- Validasi (unique, min 8)
- User Tersimpan
- Login untuk dapat token

LOGIN: User 
- Input login (username/email) + password
- Validasi kredensial
- Generate Token (Sanctum)
- Token dikembalikan

LOGOUT: User 
- Kirim token
- Token dihapus dari database
- Sesi berakhir

CREATE TODO: User (Auth) 
- Isi judul + deskripsi
- Validasi
- Todo tersimpan (status: Belum Selesai)

LIST TODO: User (Auth) 
- Minta daftar
- Sistem tampilkan semua todo milik user
- Diurutkan terbaru

DETAIL TODO: User (Auth) 
- Pilih todo by ID
- Sistem tampilkan detail

UPDATE TODO: User (Auth) 
- Pilih todo
- Edit judul / deskripsi / status
- Validasi
- Simpan

COMPLETE TODO: User (Auth) 
- Centang selesai
- is_completed = true
- Todo tertandai selesai

DELETE TODO: User (Auth) 
- Pilih todo
- Konfirmasi hapus
- Todo dihapus

2. UI/UX Design

Salah satu acuan pembuatan RESTful API adalah kebutuhan bisnis dan kebutuhan pengguna. UI/UX dapat digunakan sebagai acuan untuk membantu mendefinisikan API yang dibutuhkan. Dalam banyak kasus, praktik yang baik adalah membuat Business Flow terlebih dahulu, kemudian UI/UX, lalu menyusun API Documentation berdasarkan kebutuhan UI/UX tersebut. (dalam kasus ini yang dibuat adalah api spec dulu seharusnya UI/UX, karena project simple, uinya dibuatkan saja oleh oleh AI, fokus ke RESTful API)

Register Form

Login Form

Todo List

3. API Documentation

Dokumentasi API menggunakan OpenAPI karena merupakan salah satu standar yang paling umum digunakan untuk mendeskripsikan REST API. bukan satu-satunya standar, tetapi memang yang paling populer saat ini. Seperti sebelumnya API Documentation itu bebas bisa menggunakan apa saja bahkan Pdf/Word. 

Pada artikel ini hanya menampilkan daftar endpoint (Method + URL) yang akan digunakan. Dokumentasi OpenAPI lengkap yang berisi request, response, schema, validasi, dan autentikasi dapat dilihat pada https://github.com/junaedimg/todolist-restfulapi/tree/main/docs.

# User
POST    /api/register
POST    /api/login
DELETE  /api/logout
GET     /api/users/current
PATCH   /api/users/current

# Todo
GET     /api/todos
POST    /api/todos
GET     /api/todos/{todoId}
PATCH   /api/todos/{todoId}
DELETE  /api/todos/{todoId}

4. Develop RESTful API

berikut reponya https://github.com/junaedimg/todolist-restfulapi.git. Untuk back end API menggunakan Laravel 13, dengan api route seperti ini. 

<?php

use App\Http\Controllers\TodoController;
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;

Route::post('/register', [UserController::class, 'register']);
Route::post('/login', [UserController::class, 'login']);

Route::middleware('auth:sanctum')->group(function () {
    Route::post('/users/logout', [UserController::class, 'logout']);
    Route::get('/users/current', [UserController::class, 'current']);
    Route::patch('/users/current', [UserController::class, 'update']);

    Route::get('/todos', [TodoController::class, 'index']);
    Route::post('/todos', [TodoController::class, 'store']);
    Route::get('/todos/{id}', [TodoController::class, 'show']);
    Route::patch('/todos/{id}', [TodoController::class, 'update']);
    Route::delete('/todos/{id}', [TodoController::class, 'destroy']);
});

 

 

Learning Notes

dengan contoh table user dengan filed 

id
username
password
api_token

inti pemahamannya gunakan PUT ketika mengubah representasi lengkap field yang dapat diubah. misal username dan passwrod karena 

gunakan PATCH ketika mengubah salah satu dari username atau password

 

 

Referensi 

PLAYLIST YOUTUBE - REST API (Web Programming Unpas)

PLAYLIST YOUTUBE - REST API (Programmer Zaman Now)

YOUTUBE - Tutorial Laravel RESTful API (Programmer Zaman Now)

Ilustrasi API Youtube

https://bif.telkomuniversity.ac.id/apa-itu-api/

https://www.ibm.com/id-id/think/topics/api

https://www.ibm.com/id-id/think/topics/rest-apis

https://idwebhost.com/blog/authentication-vs-authorization/

 

Tinggalkan komentar

Nama yang akan ditampilkan pada komentar.

🔔 Email opsional untuk menerima notifikasi balasan.

Tulis komentar Anda dengan jelas dan tetap sopan.

P
pnzxxqemsg • 2 minggu yang lalu

lfvyfwzoxnrnsmuteltylookhmphhe

M
mhjfgfrtkn • 2 minggu yang lalu

yxpotjmwzfpjthdeiugnjrlqjiltoe

I
iqzzhifdwh • 2 minggu yang lalu

psoffwteoxjnhfwztexwnoyojvsjxm