Sebelumnya kita sudah membangun Task API secara lengkap dengan metode Function-Based Views (FBV). Kita menulis function Python biasa, men-decorate-nya dengan @api_view, dan menggunakan branching model if request.method == "GET" untuk menangani HTTP method yang berbeda-beda di dalam function yang sama.
Pendekatan tersebut bisa dilakukan, tapi ada masalah pada arsitektur kodenya. Semakin besar sebuah view (lebih banyak method, lebih banyak validasi, lebih banyak setup code yang dipakai bersama), satu function dengan rantai if statement yang panjang akan semakin sulit dibaca dan sulit digunakan ulang. Materi ini memperkenalkan tool berikutnya di DRF: Class-Based Views, khususnya class APIView.
Di akhir materi ini, kita akan membangun ulang Task API yang sama dengan yang sebelumnya ada di materi Function-Based Views, tapi kali ini menggunakan class, bukan function. Setelah menyelesaikan materi kali ini, kita akan benar-benar memahami kenapa DRF memberikan opsi ini.
Berikut ide dasarnya dalam satu kalimat: daripada menggunakan satu function yang bercabang berdasarkan request.method, kita menulis satu class di mana setiap HTTP method punya method-nya sendiri.
Bandingkan bentuk dari kedua pendekatan ini:
| |
dengan
| |
Perhatikan apa yang berubah. Daripada mengecek request.method menggunakan if statement, kita cukup menulis method bernama get dan method bernama post. DRF (melalui Django di baliknya) akan melihat method dari request yang masuk dan otomatis memanggil method yang sesuai pada class kita. Kalau client mengirim request GET, method get() kita yang akan berjalan. Kalau mereka mengirim POST, method post() kita yang akan berjalan. Kita tidak pernah perlu menulis if check itu sendiri.
Ini bukan konsep yang benar-benar baru. Ini adalah siklus request/response yang sama dengan yang kita pelajari di materi Function-Based Views (method, path, headers, body yang masuk; status code, headers, body yang keluar). Hanya cara kita mengorganisir kode kita saja yang berubah.
Kenapa kita membutuhkan ini?
Kita mungkin bertanya: “Kalau FBV sudah berfungsi, kenapa kita perlu belajar cara kedua untuk melakukan hal yang sama?”
Berikut alasan-alasan praktisnya:
Pemisahan logic yang lebih rapi
Dengan FBV, semua logic untuk setiap method berada di dalam satu function body, hanya dipisahkan oleh if statement. Dengan CBV, setiap method punya tempatnya sendiri. Tidak ada kemungkinan kita tidak sengaja menulis logic GET di dalam block yang seharusnya untuk POST, karena keduanya adalah method yang terpisah.
Setup code yang dipakai bersama
Bayangkan setiap method di sebuah view perlu mengecek sesuatu terlebih dahulu, misalnya, mengambil object tertentu dari database berdasarkan primary key-nya. Dengan FBV, kita harus mengulang logic lookup tersebut (atau block try/except-nya) di setiap if branch, atau menariknya keluar sebelum branch-branch tersebut dengan cara yang agak awkward. Dengan class, kita bisa mendefinisikan satu helper method saja (seperti get_object()) dan memanggilnya dari get(), put(), dan delete() tanpa perlu mengulang-ulang.
Inheritance dan reuse
Class bisa melakukan inherit dari class lainnya. Ini berarti kita bisa membangun view “dasar” dengan behavior yang umum dan membiarkan view lainnya melakukan extend terhadapnya. Kita belum terlalu banyak menggunakan ini di materi kali ini, tapi ini akan menjadi sangat powerful begitu kita sampai di Generic Views pada materi selanjutnya. APIView adalah dasar dari semua hal lainnya di sistem class-based milik DRF.
Permission dan authentication hook yang sudah tersedia
Ini adalah alasan yang signifikan, dan kita akan membahasnya secara khusus nanti di bagian bawah. APIView memberi kita class-level attribute (permission_classes, authentication_classes) yang terhubung langsung ke sistem authentication dan permission milik DRF. Dengan FBV, kita perlu decorator terpisah (@permission_classes, @authentication_classes) yang ditumpuk di atas @api_view. Dengan CBV, ini cukup menjadi sebuah attribute pada class-nya, yang menurut banyak developer lebih natural untuk dibaca dan di-maintain.
Ini bukan berarti FBV itu “salah”. FBV masih bagus untuk endpoint yang sangat kecil, sederhana, dan one-off. Tapi seiring backend API kita berkembang, kita akan semakin mengandalkan pattern class-based, jadi penting untuk membangun mental model ini dari sekarang.
Class APIView
APIView adalah class yang disediakan oleh DRF. Ini adalah versi class-based dari decorator @api_view. Saat kita menulis view class, kita melakukan inherit dari APIView:
| |
Mari kita baca baris per baris.
from rest_framework.views import APIView
Perhatikan bahwa import path-nya berbeda dari @api_view. Decorator api_view berada di rest_framework.decorators. Class APIView berada di rest_framework.views. Ini mudah tertukar saat kita masih baru, jadi akan membantu kalau kita ingat: decorator untuk function berasal dari decorators, class berasal dari views.
class HelloView(APIView):
Ini adalah class Python biasa yang di-inherit dari APIView. Semua hal spesial soal bagaimana class ini berperilaku (parsing request.data, membungkus request ke dalam object Request milik DRF, menangani authentication, dan lain-lain) berasal dari apa yang di-inherit dari APIView. Kita tidak membangun mesin-nya. Kita hanya mencolok kebutuhan kita ke mesin tersebut.
def get(self, request):
Ini adalah instance method Python biasa. Penamaan get di sini tidak sembarangan. DRF (melalui class View milik Django di baliknya) melihat HTTP method dari request yang masuk, mengubahnya menjadi lowercase, lalu mencoba memanggil method dengan nama yang persis sama pada class kita. Request GET memanggil get(). Request POST memanggil post(). Request PUT memanggil put(). Request DELETE memanggil delete(). Request PATCH memanggil patch().
Perhatikan bahwa parameter pertamanya adalah self, karena ini adalah method pada sebuah class, bukan function yang berdiri sendiri. Parameter kedua adalah request, sama persis seperti di dunia FBV. Ini tetap object Request milik DRF yang sudah ditingkatkan, dengan request.data, request.query_params, dan request.user semuanya tersedia, persis seperti yang kita pelajari di materi Function-Based Views.
Apa yang terjadi kalau client mengirim method yang tidak kita definisikan?
Kalau client mengirim request DELETE ke HelloView, dan kita tidak pernah mendefinisikan method delete(), DRF akan otomatis merespon dengan 405 Method Not Allowed. Kita mendapatkan ini secara gratis, persis seperti perilaku whitelist method pada @api_view(["GET"]) di materi Function-Based Views. Kita tidak perlu menulis kode tambahan apapun untuk menolak method yang tidak didukung.
Implementasi get(), post(), put(), delete()
Mari kita lihat seperti apa view yang lebih lengkap, berdampingan dengan versi FBV dari materi Function-Based Views, supaya perbedaannya jelas terlihat.
List view (GET all, POST new)
Versi FBV (dari materi Function-Based Views):
| |
Versi CBV (yang sedang kita pelajari sekarang):
| |
Baca kedua kode ini berdampingan pelan-pelan dan teliti. Isi dari setiap block logic-nya hampir identik. Yang berubah hanya pembungkus luarnya: daripada satu function dengan if request.method == "GET", kita punya dua method, get dan post, dan if check-nya menghilang karena nama method itu sendiri yang memberi tahu DRF kapan harus menjalankannya.
Detail view (GET satu, PUT update, DELETE)
Versi FBV (dari materi Function-Based Views):
| |
Versi CBV:
| |
Ini adalah momen di mana pendekatan class-based mulai terlihat kelebihannya. Perhatikan get_object(self, pk). Ini adalah helper method kecil yang kita tulis sendiri. Ini tidak diwajibkan oleh DRF, tapi ini adalah pattern yang sangat umum dan berguna. Ketiga HTTP method (get, put, delete) membutuhkan logic lookup yang sama: mencari Task berdasarkan primary key-nya, atau mengembalikan error 404 yang benar kalau tidak ditemukan. Daripada mengulang block try/except tersebut tiga kali, kita menulisnya satu kali saja dan memanggil self.get_object(pk) dari setiap method.
Http404 dibandingkan membuat Response secara manual
Perhatikan bahwa kita menggunakan raise Http404 daripada me-return Response({"detail": "Not found."}, status=404) secara manual. Ini adalah exception bawaan Django untuk “ini tidak ada”. DRF secara otomatis catch Http404 di manapun di dalam method view dan mengubahnya menjadi JSON response 404 Not Found yang benar untuk kita. Ini berfungsi karena DRF membungkus seluruh logic dispatch view kita di dalam exception handling. Kita tidak perlu menulis Response(...)-nya sendiri. Import seperti ini:
| |
Kedua pendekatan (raise Http404 atau me-return Response dengan status 404 secara manual) sama-sama dapat digunakan. Raise Http404 sedikit lebih umum digunakan di dunia DRF begitu kita menggunakan class, karena ini memungkinkan kita men-centralize case “not found” di satu helper method tanpa helper tersebut perlu tahu tentang object Response sama sekali. Tapi kita akan tetap melihat Response(status=404) secara manual digunakan di banyak codebase, keduanya sama-sama benar.
Logic yang self-contained untuk single endpoint
Mari kita melambat sebentar untuk membahas konsep yang disebutkan di outline materi ini: “logic yang self-contained untuk single endpoint”. Ini sebenarnya berkaitan dengan apa yang baru saja kita lihat pada get_object(), mari kita pahami idenya secara eksplisit.
Sebuah class adalah sebuah container. Semua yang dibutuhkan single endpoint (logic lookup-nya, keunikan validasinya, method helper privat kecil apapun) bisa ada di dalam satu class tersebut, dan scope-nya hanya untuk class itu saja. Tidak ada yang leak keluar dan mempengaruhi view lain, begitu juga tidak ada juga leak dari view lain yang masuk.
Bayangkan sebuah toolbox. Setiap subclass APIView adalah toolbox-nya sendiri. TaskDetail punya tool get_object()-nya sendiri di dalam box-nya sendiri. Kalau nanti kita membangun view yang benar-benar berbeda, katakanlah CommentDetail, dia akan mendapatkan toolbox terpisahnya sendiri dengan method get_object()-nya sendiri (mencari Comment, bukan Task). Keduanya tidak saling mengganggu, dan kita tidak perlu khawatir tentang konflik dalam penamaan antara view yang tidak berhubungan, karena setiap method ter-scope ke class-nya sendiri.
Perubahan dalam cara berpikir pada CBV jika dibandingkan dengan FBV terlihat subtle namun sebenarnya penting. Dengan function, kalau kita ingin membagikan sebuah helper antara task_list dan task_detail, kita perlu mendefinisikan helper tersebut di luar kedua function tersebut (mungkin di level module / awal dari file Python) terlebih dahulu, kemudian import ke keduanya. Sementara pada class, terutama begitu kita sampai ke inheritance di materi selanjutnya, cara berbagi logika antar beberapa view adalah dengan membuat parent class yang dipakai bersama. Kita belum melakukan itu di materi ini (kita tidak akan membangun base class bersama hari ini), tapi memahami bahwa class mengelompokkan logic yang berhubungan menjadi dasar mengapa tipe view yang lebih advanced milik DRF (Generic Views, ViewSets) dibangun sebagai class hierarchy.
Permission dan authentication hook
Mulai sekarang kita akan memakai istilah hook. Hook kurang lebih berarti tempat untuk plug in config kita. Hook permission dan authentication adalah salah satu alasan terkuat untuk memilih APIView seiring berkembangnya codebase kita. Mari kita pahami konsepnya dari apa yang sudah kita pelajari.
Rekap singkat: authentication vs permission
Sebelumnya di materi Initial Settings Configuration, kita sudah belajar perbedaannya dan sekarang kita pahami kembali:
- Authentication menjawab pertanyaan: “Siapa yang membuat request ini?”
- Permission menjawab pertanyaan: “Apakah user ini diizinkan melakukan ini?”
Keduanya berjalan sebagai sebuah pipeline, dijalankan sebelum method get(), post(), maupun method lainnya, seperti pada skema berikut:
| |
Ini penting: kalau permission atau authentication gagal, kode get() atau post() kita bahkan tidak akan tereksekusi. DRF menghentikan request tersebut sebelum sampai ke logic kita.
Mengatur authentication dan permission pada view dengan APIView
Kita dapat mengontrol behavior ini dengan dua class attribute:
| |
authentication_classes
authentication_classes adalah kumpulan class yang dicoba oleh DRF, secara berurutan, untuk mencari tahu siapa yang membuat request. Ini adalah opsi yang sama dengan yang kita pelajari di materi Initial Settings sebelumnya (SessionAuthentication, BasicAuthentication, TokenAuthentication, dan lain-lain). Kalau tidak ada satupun yang berhasil, request.user akan menjadi AnonymousUser.
permission_classes
permission_classes adalah kumpulan class yang dicek oleh DRF, secara berurutan, untuk memutuskan apakah request.user (apapun yang dihasilkan oleh authentication) diizinkan untuk melanjutkan. Juga merupakan opsi yang sama dari materi Initial Settings sebelumnya (AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly).
Kenapa CBV lebih nyaman dibandingkan FBV
Dengan FBV, untuk mendapatkan hasil yang sama kita perlu menumpuk decorator:
| |
Cara diatas memang bisa digunakan, tapi perhatikan bagaimana decorator-decoratornya menumpuk satu sama lain. Sementara dengan class, konfigurasi yang sama hanya menjadi dua baris saja di dalam class body-nya, berdampingan, dan mudah untuk dibaca sekilas:
| |
Global default vs per-view override
Pada materi Initial Settings kita sudah pelajari bahwa apapun yang kita masukkan ke REST_FRAMEWORK["DEFAULT_PERMISSION_CLASSES"] di settings.py adalah fallback untuk semua view. Men-set permission_classes langsung pada sebuah class, seperti yang baru kita lakukan, akan meng-override global default tersebut hanya untuk view spesifik ini saja. Ini persis pattern override yang sudah kita lihat sebelumnya di materi Initial Settings:
| |
Ini memungkinkan kita untuk tetap menjaga global default yang strict (aman secara default) sambil membuka endpoint tertentu secara intentional, satu class pada satu waktu.
Apa yang terjadi kalau kita tidak menyertakan attribute ini sama sekali?
Kalau kita tidak men-set authentication_classes atau permission_classes sama sekali pada class kita, DRF akan fallback ke apapun yang dikonfigurasi secara global di settings.py di bagian REST_FRAMEWORK. Ini adalah behavior fallback global yang sama dengan yang kita pelajari di materi Initial Settings. Untuk latihan materi ini, kita akan men-set permission_classes = [AllowAny] secara eksplisit supaya kita bisa melakukan test secara bebas tanpa perlu login, persis seperti pendekatan fbv_lab di materi Function-Based Views.
Kapan menggunakan APIView dibandingkan shortcut lainnya
DRF sebenarnya menawarkan beberapa layer “shortcut” di atas APIView (Generic Views, Mixins, ViewSets), yang akan kita temui di materi selanjutnya. Mari kita lihat posisi APIView secara apa adanya, agar kita dapat membangun insting yang benar sejak awal.
Berikut adalah framework untuk mengambil keputusan:
| Situasi | Pilihan Terbaik |
|---|---|
| Endpoint one-off yang cepat dengan logic yang tidak biasa (bukan CRUD sederhana) | Function-Based View atau APIView |
| Behavior CRUD standar (list, create, retrieve, update, delete) yang mengikuti pattern yang umum | Generic Views (materi selanjutnya) |
| Endpoint yang tidak di-mapping secara clean ke model apapun (health check, search endpoint yang bersinggungan dengan banyak model, custom report) | APIView |
| Kita butuh kontrol yang sangat eksplisit dan mudah dibaca atas setiap baris yang terjadi per HTTP method | APIView |
| Kita baru mulai belajar dan ingin melihat dengan tepat bagaimana siklus request/response bekerja, tanpa shortcut yang tersembunyi | Function-Based View atau APIView |
| Kita mengulang pattern list/create/retrieve/update/delete yang persis sama di banyak model | Generic Views atau ViewSets (materi selanjutnya), karena APIView berarti kita harus menulis boilerplate tersebut setiap saat |
Tradeoff sebenarnya
APIView adalah titik tengah antara FBV dan Generic Views/ViewSets di DRF. APIView memberi kita struktur yang lebih dibandingkan function biasa, tapi tetap mengharuskan kita menulis setiap method body-nya sendiri. Generic Views dan ViewSets (yang akan datang di materi selanjutnya) akan menangani banyak boilerplate tersebut secara otomatis, dengan konsekuensi menjadi kurang eksplisit tentang apa yang terjadi di baliknya.
Untuk saat ini, selagi kita masih membangun mental model tentang siklus request/response, APIView adalah sweet spot-nya. Ini mengajarkan kita struktur yang menjadi dasar dari Generic Views dan tetap memperlihatkan dengan jelas apa yang terjadi di baliknya. Ketika kita akhirnya belajar Generic Views nanti, kita akan langsung mengenali get_object(), permission_classes, dan authentication_classes, karena kita sudah membangun pemahaman itu di sini.
Rule of thumb untuk saat ini: kalau kita tidak yakin apakah sebuah endpoint itu “CRUD sederhana” atau “custom logic”, gunakan APIView. Ini tidak pernah menjadi pilihan yang salah, hanya terkadang menjadi pilihan yang lebih verbose.
Latihan
Kita akan membangun ulang Task API yang serupa dari materi Function-Based Views, tapi kali ini dengan class-based views, di dalam app baru yang sepenuhnya independen.
Latihan ini akan menghasilkan:
GET /tasks/: menampilkan list semua taskPOST /tasks/: membuat task baruGET /tasks/<pk>/: mengambil satu taskPUT /tasks/<pk>/: update satu taskDELETE /tasks/<pk>/: menghapus satu task
Endpoint yang sama dengan materi Function-Based Views, behavior yang sama, struktur internal yang berbeda.
Buat app dan daftarkan
| |
Tambahkan ke INSTALLED_APPS di config/settings.py:
| |
Buat model di cbv_lab/models.py
Ini sengaja dibuat dengan bentuk yang sama seperti fbv_lab.Task, supaya kita bisa fokus sepenuhnya pada perbedaan layer view-nya, bukan belajar model yang baru.
| |
Buat dan apply migrations
| |
Buat serializer di cbv_lab/serializers.py
| |
Pattern yang sama dengan yang sudah kita ketahui dari materi Serializer Basics sampai Serializer Methods and Customization, dan identik dengan yang ada di materi Function-Based Views. Tidak ada yang baru di sini.
Buat views di cbv_lab/views.py
Baca setiap baris dengan teliti. Comment-nya menjelaskan setiap keputusan yang diambil.
| |
Kenapa tidak ada method whitelist kali ini?
Dengan @api_view(["GET", "POST"]) di materi Function-Based Views, kita harus mendaftarkan secara manual method mana saja yang diizinkan. Dengan APIView, kita tidak mendaftarkan apapun. DRF akan melihat method mana saja yang kita definisikan (get, post, dan lain-lain) dan secara otomatis hanya mengizinkan method tersebut. Kalau kita tidak pernah mendefinisikan patch(), request PATCH ke TaskList akan otomatis mendapat 405 Method Not Allowed, tanpa kode tambahan apapun dari kita.
Hubungkan URL-nya
Class-based view membutuhkan satu langkah tambahan yang tidak dibutuhkan oleh function-based view: memanggil .as_view() saat kita mendaftarkannya di urls.py. Kita akan jelaskan alasannya tepat setelah kodenya.
Buat cbv_lab/urls.py:
| |
Kenapa .as_view()?
Ini adalah perbedaan syntax paling besar antara FBV dan CBV, jadi mari kita pahami dengan jelas.
Sistem URL routing milik Django mengharapkan untuk memanggil sebuah function biasa untuk setiap request yang masuk, yang menerima request sebagai argument pertamanya. Tapi TaskList adalah sebuah class, bukan function. Kita tidak bisa mengarahkan URL secara langsung ke sebuah class.
.as_view() adalah method spesial (di-inherit dari base class View milik Django, yang menjadi dasar APIView) yang mengubah class kita menjadi sesuatu yang berperilaku seperti function dari sudut pandang Django. Setiap kali ada request yang masuk, .as_view() membuat instance baru dari class kita di belakang layar, dan memanggil method yang tepat (get, post, dan lain-lain) pada instance tersebut berdasarkan HTTP method dari request-nya.
Kita tidak perlu memahami internal-nya secara dalam sekarang. Aturan yang perlu diingat sederhana: setiap kali kita mendaftarkan class-based view di urls.py, kita panggil .as_view() padanya. Melupakan hal ini adalah salah satu kesalahan pemula yang paling umum, dan Django akan raise error yang jelas kalau kita lupa (sesuatu seperti “view must be a function” atau “as_view() missing”).
Daftarkan URL app di project
Buka config/urls.py dan include URL app baru kita, langsung di bawah URL materi Function-Based Views:
| |
Endpoint baru kita sekarang menjadi:
GET /api/cbv/tasks/POST /api/cbv/tasks/GET /api/cbv/tasks/1/PUT /api/cbv/tasks/1/DELETE /api/cbv/tasks/1/
Tambahkan sample data
| |
| |
Test endpoint di browser atau Postman
Keluar dari shell setelah selesai (exit() atau Ctrl-D), lalu jalankan server di bawah ini.
| |
Kunjungi http://127.0.0.1:8000/api/cbv/tasks/ di browser. Kita seharusnya melihat browsable API interface yang sama seperti yang kita lihat di materi Function-Based Views, menampilkan list lima task yang sudah kita seed.
Coba http://127.0.0.1:8000/api/cbv/tasks/1/ untuk melihat satu task.
Coba yang tidak ada, http://127.0.0.1:8000/api/cbv/tasks/9999/, dan pastikan kita mendapat response 404 yang clean, bukan server error.
Test full request/response cycle di shell
Pendekatan simulasi yang sama dengan materi Function-Based Views, hanya saja kali ini kita memanggil method class baru kita secara langsung untuk melihatnya bekerja secara terisolasi.
| |
| |
Alur lengkap dari request hingga response
| |
Langkah baru yang penting dibandingkan diagram di materi Function-Based Views adalah APIView.dispatch(). Ini adalah mesin yang kita dapatkan secara gratis lewat inheritance, dan di sinilah persis tempat authentication dan permission check terjadi, sebelum method kita bahkan mulai berjalan.
Tabel perbandingan: Function-Based View vs Class-Based View (APIView)
| Feature | Function-Based View (@api_view) | Class-Based View (APIView) |
|---|---|---|
| Bagaimana method ditangani | Satu function, if request.method == "..." | Satu method per HTTP verb (get, post, put, delete) |
| Method whitelist | List eksplisit yang diberikan ke decorator | Implisit, berdasarkan method mana yang kita definisikan |
| Registrasi URL | path("tasks/", views.task_list) | path("tasks/", views.TaskList.as_view()) |
| Setup logic yang dipakai bersama (misalnya object lookup) | Diulang di setiap if block, atau ditarik keluar menjadi function di level module | Sebuah method pada class-nya (misalnya get_object()), dipanggil dari beberapa method |
| Permission dan authentication | Decorator yang ditumpuk di atas (@permission_classes, @authentication_classes) | Class attribute (permission_classes, authentication_classes) |
| Cocok untuk | Endpoint yang kecil, sederhana, one-off | Endpoint dengan shared logic, atau sebagai dasar untuk Generic Views nanti |
| Keterbacaan saat berkembang | Semakin sulit dibaca seiring bertambahnya method dan branch | Tetap terorganisir karena setiap method secara fisik terpisah |
Kesalahan yang sering terjadi
Lupa
.as_view()diurls.py. Django butuh sesuatu yang callable, bukan class polos.path("tasks/", views.TaskList)akan raise error.Menamai method dengan sesuatu selain HTTP verb dalam lowercase. Kalau kita menulis
def GET(self, request):(uppercase) ataudef list(self, request):, DRF tidak akan mengenalinya sebagai handler untuk requestGET. Harus persisget,post,put,patch, ataudelete, semuanya lowercase.Lupa
selfsebagai parameter pertama. Setiap method di dalam sebuah class membutuhkanself. Menulisdef get(request):tanpaselfakan raiseTypeErrorsaat Django mencoba memanggilnya.Tidak men-set
permission_classesdan terkejut ketika sebuah view tiba-tiba membutuhkan login. Kalau kita tidak men-set-nya secara eksplisit, view tersebut akan fallback ke apapun yang dikonfigurasi secara global disettings.pydi bawahREST_FRAMEWORK["DEFAULT_PERMISSION_CLASSES"], yang mungkin bukanAllowAny.Menulis shared lookup logic (seperti
get_object()) tapi lupa untuk benar-benar memanggilnya dari setiap method yang membutuhkannya, sehingga menyebabkan behavior yang tidak konsisten antaraget(),put(), dandelete().Tertukar antara
Http404(daridjango.http) dengan exception class milik DRF sendiri.raise Http404berfungsi karena DRF secara khusus men-catch-nya, tapi mudah untuk tidak sengaja mengimport hal yang salah kalau kita tidak memperhatikan.Menganggap
APIViewotomatis menangani boilerplate CRUD seperti yang akan dilakukan Generic Views nanti.APIViewtetap mengharuskan kita menulis setiap baris logic sendiri. Ini wajar dan benar pada tahap ini.
Ringkasan
| |
Foto cover oleh fallout766 dari Unsplash
