7
Endpoint API dan Skema OpenAPI
backend/config/urls.py menyatukan dua kelompok endpoint: rute yang dihasilkan SimpleRouter dan view khusus yang dipasang langsung di urlpatterns. Semua rute berada di bawah prefiks api/, karena router disertakan lewat path("api/", include(router.urls)) backend/config/urls.py:22-481.
Peta endpoint per modul
SimpleRouter didaftari satu per satu untuk 14 viewset, lalu hasilnya disertakan bersama rute khusus di dalam urlpatterns backend/config/urls.py:22-481. Pengelompokan berikut mengikuti modul pemilik viewset-nya.
graph TD
URL["config/urls.py"] --> ROUTER["SimpleRouter: 14 register"]
URL --> KHUSUS["urlpatterns khusus"]
ROUTER --> MP["modul produk"]
ROUTER --> MS["modul stok"]
ROUTER --> MB["modul pembelian"]
ROUTER --> MA["modul akun"]
MP --> P1["kategori, produk, satuan, harga"]
MS --> S1["batch, mutasi, barang-masuk, opname"]
MB --> B1["pelanggan, transaksi, retur"]
MA --> A1["pengguna, peran, log-aktivitas"]
KHUSUS --> K1["api/kesehatan/"]
KHUSUS --> K2["api/auth/sesi/"]
KHUSUS --> K3["api/dasbor/"]
KHUSUS --> K4["api/laporan/penjualan, stok, piutang, terlaris"]
style URL fill:#f59e0b,color:#000
style KHUSUS fill:#f59e0b,color:#000
style ROUTER fill:#2d7d46,color:#fff
style K1 fill:#2d7d46,color:#fff
style K4 fill:#8b5cf6,color:#fff
%% fig: Peta endpoint dari SimpleRouter dan urlpatterns
%% desc: Router menghasilkan empat kelompok endpoint per modul, sementara kesehatan, sesi, dasbor, dan empat view laporan dipasang langsung di urlpatterns.| Rute | viewset | Modul | Rujukan |
|---|---|---|---|
/api/kategori/ | KategoriViewSet | produk | backend/produk/views.py:33-432 |
/api/produk/ | ProdukViewSet | produk | backend/produk/views.py:46-653 |
/api/satuan/ | SatuanViewSet | produk | backend/produk/views.py:155-1614 |
/api/harga/ | HargaViewSet | produk | backend/produk/views.py:164-1735 |
/api/batch/ | BatchViewSet | stok | backend/stok/views.py:24-266 |
/api/mutasi/ | MutasiViewSet | stok | backend/stok/views.py:57-597 |
/api/barang-masuk/ | BarangMasukViewSet | stok | backend/stok/views.py:73-758 |
/api/opname/ | OpnameViewSet | stok | backend/stok/views.py:91-999 |
/api/pelanggan/ | PelangganViewSet | pembelian | backend/pembelian/views.py:32-4110 |
/api/transaksi/ | TransaksiViewSet | pembelian | backend/pembelian/views.py:67-7711 |
/api/retur/ | ReturViewSet | pembelian | backend/pembelian/views.py:182-18412 |
/api/pengguna/ | PenggunaViewSet | akun | backend/akun/views.py:47-5613 |
/api/peran/ | PeranViewSet | akun | backend/akun/views.py:79-8314 |
/api/log-aktivitas/ | LogAktivitasViewSet | akun | backend/akun/views.py:86-8815 |
Empat viewset hanya menyediakan sebagian aksi: KategoriViewSet membatasi http_method_names pada get, post, dan patch saja backend/produk/views.py:33-432. ProdukViewSet menambahkan komentar bahwa penghapusan tidak disediakan karena produk lama dinonaktifkan backend/produk/views.py:46-653. BatchViewSet dan MutasiViewSet hanya list dan retrieve backend/stok/views.py:24-266. TransaksiViewSet memilih TransaksiSerializer untuk list dan TransaksiDetailSerializer untuk aksi lain backend/pembelian/views.py:67-7711.
view khusus di luar router
Rute khusus dideklarasikan sebagai daftar urlpatterns backend/config/urls.py:38-4816.
| Rute | view | Perilaku | Rujukan |
|---|---|---|---|
/api/kesehatan/ | kesehatan | mengembalikan {"status": "ok"} | backend/akun/views.py:29-3017 |
/api/_allauth/ | include("allauth.headless.urls") | rute headless allauth | backend/config/urls.py:38-4816 |
/api/auth/sesi/ | SesiView | ensure_csrf_cookie plus AllowAny | backend/akun/views.py:33-4418 |
/api/dasbor/ | DasborView | isi mengikuti izin pengguna | backend/laporan/views.py:166-17219 |
/api/laporan/* | LaporanPenjualanView, LaporanTerlarisView, LaporanStokView, LaporanPiutangView | daftar baris laporan | backend/laporan/views.py:43-4620 |
api/kesehatan/ dipanggil langsung oleh healthcheck container lewat HTTP, jadi rute ini dikecualikan dari pengalihan SSL lewat SECURE_REDIRECT_EXEMPT backend/config/settings.py:143-14421.
Paginasi dan filter query string
Paginasi default memakai Paginasi dengan page_size = 25, parameter pengubah bernama ukuran, dan batas max_page_size = 200 backend/inti/paginasi.py:4-722. Kelas itu dipasang sebagai DEFAULT_PAGINATION_CLASS di REST_FRAMEWORK backend/config/settings.py:147-15923. KategoriViewSet dan PeranViewSet mematikan paginasi dengan pagination_class = None backend/produk/views.py:33-432 dan backend/akun/views.py:79-8314.
Filter dibaca langsung dari self.request.query_params di get_queryset:
| Rute | Query string | Rujukan |
|---|---|---|
/api/produk/ | q, kategori, aktif=1, status=habis|menipis|aman | backend/produk/views.py:74-8824 |
/api/harga/ | produk | backend/produk/views.py:164-1735 |
/api/batch/ | produk, ada_sisa=1, q, status=kedaluwarsa | backend/stok/views.py:32-4525 |
/api/mutasi/ | produk, batch, jenis | backend/stok/views.py:63-7026 |
/api/opname/ | status | backend/stok/views.py:101-10727 |
/api/pelanggan/ | q, aktif=1 | backend/pembelian/views.py:59-6428 |
/api/transaksi/ | q, pelanggan, dari, sampai, status, status_bayar=lunas|belum_lunas|jatuh_tempo | backend/pembelian/views.py:94-11329 |
/api/retur/ | q | backend/pembelian/views.py:190-19530 |
Parameter ekspor dan periode laporan
Parameter ekspor dideklarasikan sebagai OpenApiParameter("ekspor", str, enum=["xlsx", "pdf"]), bersama PARAM_PERIODE yang berisi dari dan sampai bertipe DATE backend/laporan/views.py:29-3331. LaporanView.get memilih keluaran dari nilai parameter itu: ke_xlsx, ke_pdf, atau Response berisi data serializer backend/laporan/views.py:54-6132.
sequenceDiagram
participant K as Klien
participant L as LaporanView.get
participant P as ambil_periode
participant E as laporan.ekspor
K->>L: "GET /api/laporan/penjualan/?dari&sampai&ekspor"
L->>P: "ambil_periode(request)"
P-->>L: "(dari, sampai)"
alt dari > sampai
P-->>K: "ValidationError: Tanggal awal setelah tanggal akhir."
else ekspor=xlsx
L->>E: "ke_xlsx(judul, kolom, baris, nama_file)"
else ekspor=pdf
L->>E: "ke_pdf(judul, periode, kolom, baris, nama_file)"
else tanpa ekspor
L-->>K: "Response(serializer_class(baris, many=True).data)"
end
%% fig: Siklus satu request laporan dengan parameter ekspor
%% desc: ambil_periode memvalidasi rentang tanggal, lalu get memilih berkas xlsx, berkas pdf, atau JSON sesuai nilai ekspor.ambil_periode memakai tanggal 1 bulan berjalan sebagai default dari dan hari ini sebagai default sampai; bila rentang terbalik, view melempar ValidationError({"dari": ["Tanggal awal setelah tanggal akhir."]}) backend/laporan/views.py:36-4233.
| Rute | Parameter yang dideklarasikan | Rujukan |
|---|---|---|
/api/laporan/penjualan/ | dari, sampai, ekspor, per (hari/bulan) | backend/laporan/views.py:85-9234 |
/api/laporan/produk-terlaris/ | dari, sampai, ekspor | backend/laporan/views.py:112-11435 |
/api/laporan/stok/ | ekspor | backend/laporan/views.py:137-13936 |
/api/laporan/piutang/ | ekspor | backend/laporan/views.py:161-16337 |
per hanya dibaca pada laporan penjualan, dengan nilai selain bulan diperlakukan sebagai hari backend/laporan/views.py:8238.
Custom action yang menambah endpoint
| Rute | Method | Handler | Rujukan |
|---|---|---|---|
/api/batch/{id}/kurangi/ | POST | BatchViewSet.kurangi | backend/stok/views.py:47-5439 |
/api/opname/{id}/setujui/ | POST | OpnameViewSet.setujui | backend/stok/views.py:119-12740 |
/api/opname/{id}/tolak/ | POST | OpnameViewSet.tolak | backend/stok/views.py:119-12740 |
/api/produk/{id}/foto/ | GET | ProdukViewSet.foto | backend/produk/views.py:97-10341 |
/api/produk/{id}/foto/ | POST | ProdukViewSet.unggah_foto | backend/produk/views.py:105-12342 |
/api/produk/impor/ | POST | ProdukViewSet.impor | backend/produk/views.py:125-14243 |
/api/produk/template-impor/ | GET | ProdukViewSet.template_impor | backend/produk/views.py:144-15244 |
/api/transaksi/{id}/bayar/ | POST | TransaksiViewSet.bayar | backend/pembelian/views.py:127-17945 |
/api/transaksi/{id}/ajukan-batal/ | POST | TransaksiViewSet.ajukan_batal | backend/pembelian/views.py:127-17945 |
/api/transaksi/{id}/setujui-batal/ | POST | TransaksiViewSet.setujui_batal | backend/pembelian/views.py:127-17945 |
/api/transaksi/{id}/tolak-batal/ | POST | TransaksiViewSet.tolak_batal | backend/pembelian/views.py:127-17945 |
/api/transaksi/{id}/nota/ | GET | TransaksiViewSet.nota | backend/pembelian/views.py:127-17945 |
/api/pengguna/{id}/atur-password/ | POST | PenggunaViewSet.atur_password | backend/akun/views.py:61-7646 |
/api/pengguna/{id}/reset-2fa/ | POST | PenggunaViewSet.reset_2fa | backend/akun/views.py:61-7646 |
Nama url_path dengan tanda hubung tetap ditulis di kode sebagai garis bawah: ajukan_batal dipetakan ke ajukan-batal backend/pembelian/views.py:127-17945. TransaksiViewSet.create membalas 201 dengan TransaksiDetailSerializer backend/pembelian/views.py:120-12547. unggah_foto membalas 204 setelah memeriksa settings.FOTO_MAKS_BYTE; impor memeriksa settings.IMPOR_MAKS_BYTE dan membalas HasilImporSerializer backend/produk/views.py:105-123 dan backend/produk/views.py:125-142. Kedua batas itu bernilai 2 MB dan 5 MB backend/config/settings.py:174-175.
⚠️ Satu
@actionbisa menjadi dua operasi OpenAPI.unggah_fototidak memakai@actionbaru, melainkan@foto.mapping.post, sehingga GET dan POST berbagi path/api/produk/{id}/foto/backend/produk/views.py:105-12342. Dischema.yamlkeduanya muncul sebagaiproduk_foto_retrievedanproduk_foto_createbackend/schema.yaml:933-95849.
Skema OpenAPI dan cara menjaganya selaras
schema.yaml adalah berkas openapi: 3.0.3 dengan title: Hydro API dan version: 1.0.0 backend/schema.yaml:1-450. Nilai itu berasal dari SPECTACULAR_SETTINGS, yang juga mengaktifkan COMPONENT_SPLIT_REQUEST dan memetakan enum ke MetodeBayarEnum, JenisMutasiEnum, StatusOpnameEnum, serta StatusTransaksiEnum backend/config/settings.py:161-17251. Kelas skema default adalah drf_spectacular.openapi.AutoSchema backend/config/settings.py:147-15923, dan rujukan enum hasil pemetaan itu terlihat pada MetodeBayarEnum di schema.yaml backend/schema.yaml:2974-297752.
Autentikasi tidak memakai Bearer: SkemaAutentikasiSesi mendaftarkan AutentikasiSesi sebagai skema cookieAuth bertipe apiKey pada cookie sessionid backend/inti/skema.py:4-953. Setiap operasi terproteksi mencantumkan security: - cookieAuth: [] backend/schema.yaml:312-31354, sedangkan /api/auth/sesi/ menerima cookieAuth maupun {} sehingga tetap bisa dipanggil tanpa sesi backend/schema.yaml:13-1555.
Blok paths membentang dari baris awal berkas sampai components.schemas backend/schema.yaml:1353-135456, dan blok itu dimulai dari /api/auth/sesi/ backend/schema.yaml:5-657.
Parameter laporan tergambar apa adanya di skema: /api/laporan/penjualan/ memuat dari, ekspor, per, dan sampai backend/schema.yaml:286-30958, sementara /api/laporan/piutang/ hanya memuat ekspor backend/schema.yaml:324-33359.
⚠️
schema.yamladalah hasil generate, bukan berkas yang disunting tangan. Setelahendpointberubah, jalankanmanage.py spectacular --file schema.yaml --fail-on-warndaribackend/, lalunpm run tipe-apidarifrontend/; opsi--fail-on-warnmenggagalkan perintah bila ada bagian skema yang belum terdokumentasi README.md:62-6760. Skriptipe-apimenjalankanopenapi-typescript ../backend/schema.yaml -o src/lib/api-types.tsfrontend/package.json:961.
⚠️
schema.yamlhanya memuatendpointyang dihasilkan DRF.api/kesehatan/danapi/_allauth/tidak muncul di sana, karena blokpathslangsung dimulai dari/api/auth/sesi/backend/schema.yaml:5-657.