diff --git a/api_spec.txt b/api_spec.txt index 8682759..20b2fb8 100644 --- a/api_spec.txt +++ b/api_spec.txt @@ -1,146 +1,174 @@ -API Spec - Contoh REST API (Bahasa Indonesia) +API Spec - Identity & Authorization API (Bahasa Indonesia) Ringkasan -------- -API ini adalah contoh RESTful API yang bisa dipakai untuk manajemen pengguna, item, dan pesanan. Menggunakan JSON untuk request/response. Autentikasi memakai Bearer Token (JWT). +Spesifikasi berikut disesuaikan dengan controller aktual pada aplikasi: modul Auth (OIDC + internal JWT), modul Identity (Users, Roles, Permissions) dan mekanisme otorisasi berbasis permission. Base URL -------- -- https://api.example.com/v1 +- https://api.example.com -Header Umum ------------ -- Authorization: Bearer (kecuali endpoint login/register) +Header Umum & Auth +------------------ - Content-Type: application/json - Accept: application/json +- Otentikasi dapat diberikan dalam dua cara: + 1) Cookie internal (default flow): + - raylab_jwt (internal JWT, httpOnly cookie) + - raylab_refresh (internal refresh token, httpOnly cookie) + 2) Authorization header: Bearer +- Banyak endpoint melindungi akses dengan JWT dan permission checks. Respons sukses dari controller umumnya dibungkus sebagai: + { "success": true, "data": ..., "meta": { ... } } -Autentikasi ------------ -- POST /auth/login - - Body (application/json): - { - "email": "user@example.com", - "password": "string" - } - - Response 200: - { - "access_token": "", - "token_type": "Bearer", - "expires_in": 3600 - } - - Kesalahan: 400 (invalid input), 401 (invalid credentials) +Auth (modul /auth) +------------------- +1) GET /auth/login +- Deskripsi: Mulai flow Authorization Code + PKCE. Redirect (302) ke Identity Provider. +- Query params: + - returnTo (optional) - URL tujuan setelah login +- Response: 302 Redirect -- POST /auth/register - - Body: - { - "name": "Nama User", - "email": "user@example.com", - "password": "password123" - } - - Response 201: user created (id, name, email) +2) GET /auth/callback +- Deskripsi: Endpoint callback OIDC. Menukarkan code/state, membuat internal JWT & refresh token, dan menyetel cookie httpOnly. +- Response: 302 Redirect ke returnTo atau '/' +- Cookie yang disetel: + - raylab_jwt (internal JWT, maxAge sesuai expiresIn) + - raylab_refresh (refresh token) + +3) POST /auth/logout +- Deskripsi: Invalidate internal refresh token (opsional) dan redirect ke logout identity provider. +- Body (optional): { "refreshToken": "..." } +- Response: 302 Redirect + +4) POST /auth/refresh +- Deskripsi: Tukar refresh token menjadi internal JWT baru. +- Input: refresh token di cookie raylab_refresh atau di body { "refreshToken": "..." } +- Response 200: { "success": true, "data": { "accessToken": "...", "expiresIn": 3600, ... } } + +5) GET /auth/me +- Deskripsi: Ambil data user saat ini dari internal JWT (cookie atau Authorization header). +- Response 200: { "success": true, "data": { /* user object */ } } + +Catatan: tidak ada endpoint "/auth/register" atau POST /auth/login berbasis email/password pada controller saat ini — login terjadi via OIDC dan internal session cookies. + +Users (modul /users) +-------------------- +Semua endpoint Users dijalankan di bawah guards: JwtAuthGuard, CurrentUserGuard dan PermissionGuard. Respons mengikuti format { success, data, meta }. -Endpoint Pengguna (Users) -------------------------- 1) GET /users -- Deskripsi: Mendapatkan daftar pengguna (admin) -- Query params: - - page (int, optional, default=1) - - per_page (int, optional, default=20, max=100) - - sort (string, optional, contoh: "created_at:desc") - - q (string, optional) - pencarian nama/email +- Permission: PermissionType.USER_READ +- Deskripsi: List pengguna (paged) +- Query params umum: page, per_page, sort, q - Response 200: - { - "data": [ {"id":1, "name":"...", "email":"..."} , ...], - "meta": {"page":1, "per_page":20, "total":123} - } + { "success": true, "data": [ /* user list (toResponse) */ ], "meta": { "total": 123 } } -2) GET /users/{id} -- Path params: - - id (integer, required) -- Response 200: user object -- Errors: 404 jika tidak ditemukan +2) GET /users/me +- Deskripsi: Ambil profil user saat ini (token harus ada di cookie atau header) +- Response 200: { "success": true, "data": { /* current user */ }, "meta": {} } -3) PUT /users/{id} -- Path params: id -- Body (application/json): - { - "name": "Nama Baru", - "email": "email@baru.com" - } -- Validasi: email harus format valid; name min 2 karakter -- Response 200: updated user - -4) DELETE /users/{id} -- Path params: id -- Response 204: no content -- Permissions: hanya admin - -Endpoint Item (Items) ---------------------- -1) GET /items -- Query params: - - page, per_page, sort (lihat Users) - - category (string, optional) - - min_price, max_price (decimal, optional) -- Response: list items dengan fields id, name, description, price, stock - -2) POST /items -- Body: - { - "name": "Nama Item", - "description": "Deskripsi...", - "price": 125000.50, - "stock": 10, - "category": "Elektronik" - } -- Validasi: - - name (required, max 255) - - price (required, >=0) - - stock (integer, >=0) -- Response 201: created item -- Permissions: admin atau vendor - -3) GET /items/{id} -- Response 200: item object +3) GET /users/:id +- Permission: PermissionType.USER_READ +- Deskripsi: Ambil user berdasarkan id +- Response 200: { "success": true, "data": { /* user */ }, "meta": {} } - 404 jika tidak ditemukan -4) PUT /items/{id} -- Body: fields yang boleh diupdate (name, description, price, stock, category) +4) PATCH /users/:id/enable +- Permission: PermissionType.USER_UPDATE +- Deskripsi: Enable user +- Response 200: { "success": true, "data": { /* updated user */ }, "meta": {} } + +5) PATCH /users/:id/disable +- Permission: PermissionType.USER_UPDATE +- Deskripsi: Disable user - Response 200 -5) DELETE /items/{id} -- Response 204 +6) PATCH /users/:id +- Permission: PermissionType.USER_UPDATE +- Deskripsi: Update profil user (body berisi fields yang diperbolehkan) +- Body contoh: { "name": "Nama Baru", "email": "baru@example.com" } +- Response 200: { "success": true, "data": { /* updated user */ }, "meta": {} } -Endpoint Pesanan (Orders) -------------------------- -1) POST /orders -- Body: - { - "user_id": 12, // optional jika token sudah mewakili user - "items": [ - {"item_id": 5, "quantity": 2}, - {"item_id": 7, "quantity": 1} - ], - "shipping_address": "Alamat lengkap", - "note": "Catatan opsional" - } -- Validasi: setiap item quantity >= 1 dan tersedia di stock -- Response 201: - { - "order_id": 987, - "status": "pending", - "total": 375000.00 - } +7) DELETE /users/:id +- Permission: PermissionType.USER_DELETE +- Deskripsi: Soft delete user +- Response 200: { "success": true, "data": null, "meta": {} } -2) GET /orders/{id} -- Path param: id -- Response 200: full order detail (items, prices, shipping, status) -- Permissions: hanya pemilik order atau admin +8) POST /users/:id/restore +- Permission: PermissionType.USER_UPDATE +- Deskripsi: Restore user yang di-soft-delete +- Response 200: { "success": true, "data": { /* restored user */ }, "meta": {} } -3) PATCH /orders/{id}/status -- Body: {"status": "shipped"} -- Allowed status: pending, confirmed, shipped, delivered, cancelled -- Permissions: hanya admin atau staff +Roles (modul /roles) +-------------------- +Semua route dilindungi oleh JwtAuthGuard, CurrentUserGuard dan PermissionGuard. + +1) GET /roles +- Permission: PermissionType.ROLE_READ +- Deskripsi: List roles +- Query params: page, per_page, q +- Response 200: { "success": true, "data": [ /* roles */ ], "meta": { "total": 10 } } + +2) GET /roles/:id +- Permission: PermissionType.ROLE_READ +- Deskripsi: Ambil role +- Response 200 + +3) POST /roles +- Permission: PermissionType.ROLE_CREATE +- Deskripsi: Buat role baru +- Body contoh: { "name": "editor", "description": "..." } +- Response 200: { "success": true, "data": { /* created role */ }, "meta": {} } + +4) PATCH /roles/:id +- Permission: PermissionType.ROLE_UPDATE +- Deskripsi: Update role +- Response 200 + +5) DELETE /roles/:id +- Permission: PermissionType.ROLE_DELETE +- Deskripsi: Hapus role +- Response 200: { "success": true, "data": null, "meta": {} } + +6) POST /roles/:id/permissions +- Permission: PermissionType.ROLE_UPDATE +- Deskripsi: Assign permission ke role +- Body: { "permissionId": "..." } +- Response 200: { "success": true, "data": { /* updated role */ }, "meta": {} } + +7) DELETE /roles/:id/permissions/:permissionId +- Permission: PermissionType.ROLE_UPDATE +- Deskripsi: Remove permission dari role +- Response 200 + +Permissions (modul /permissions) +------------------------------- +Semua route dilindungi oleh JwtAuthGuard, CurrentUserGuard dan PermissionGuard. + +1) GET /permissions +- Permission: PermissionType.PERMISSION_READ +- Deskripsi: List permissions +- Response 200: { "success": true, "data": [ /* permissions */ ], "meta": { "total": 20 } } + +2) GET /permissions/:id +- Permission: PermissionType.PERMISSION_READ +- Deskripsi: Ambil permission +- Response 200 + +3) POST /permissions +- Permission: PermissionType.PERMISSION_CREATE +- Deskripsi: Buat permission baru +- Body contoh: { "name": "user:create", "description": "..." } +- Response 200: { "success": true, "data": { /* created */ }, "meta": {} } + +4) PATCH /permissions/:id +- Permission: PermissionType.PERMISSION_UPDATE +- Deskripsi: Update permission +- Response 200 + +5) DELETE /permissions/:id +- Permission: PermissionType.PERMISSION_DELETE +- Deskripsi: Delete permission +- Response 200: { "success": true, "data": null, "meta": {} } Format Tanggal dan Numerik -------------------------- @@ -150,12 +178,13 @@ Format Tanggal dan Numerik Pagination ---------- - Gunakan page & per_page -- Meta object harus mengandung total, page, per_page, total_pages +- Meta object pada controller ini biasanya minimal: { total } Response Error Umum ------------------- - 400 Bad Request - payload tidak valid { + "success": false, "error": "invalid_request", "message": "Deskripsi kesalahan", "details": { "field": ["pesan validasi"] } @@ -166,38 +195,14 @@ Response Error Umum - 429 Too Many Requests - rate limit - 500 Internal Server Error -Rate Limiting -------------- -- Contoh: 1000 requests per 1 jam per API key -- Header terkait: - - X-RateLimit-Limit: 1000 - - X-RateLimit-Remaining: 750 - - X-RateLimit-Reset: 1650000000 (epoch seconds) - Keamanan dan Persyaratan ------------------------ - Semua permintaan harus lewat HTTPS (TLS 1.2+) -- Gunakan header Authorization: Bearer -- CORS: domain yang diijinkan harus didaftarkan +- Gunakan cookie httpOnly (raylab_jwt / raylab_refresh) untuk flow internal atau header Authorization: Bearer - Validasi input di server (length, tipe, range) - Sanitasi data untuk mencegah injection -Versioning ----------- -- Versi di URL: /v1/ -- Buat v2 jika ada breaking change - -Contoh Request/Response (cURL) ------------------------------ -Login: -curl -X POST "https://api.example.com/v1/auth/login" \ - -H "Content-Type: application/json" \ - -d '{"email":"user@example.com","password":"password123"}' - -Ambil daftar item: -curl "https://api.example.com/v1/items?page=1&per_page=20" \ - -H "Authorization: Bearer " - -Footer ------- -Spesifikasi ini adalah contoh umum. Sesuaikan endpoint, nama field, aturan autentikasi, dan kebijakan rate limit sesuai kebutuhan aplikasi Anda. \ No newline at end of file +Catatan Akhir +------------ +- Spesifikasi ini disesuaikan dengan controller yang ada: /auth, /users, /roles, /permissions dan mekanisme otorisasi berbasis PermissionType. +- Perhatikan bahwa detail field respons (mis. bentuk toResponse pada entitas) dapat berbeda antar resource. Untuk integrasi, gunakan endpoint /auth/me dan /users/me untuk memvalidasi data user yang tersedia. \ No newline at end of file