diff --git a/API_RESPONSE_STANDARD.md b/API_RESPONSE_STANDARD.md new file mode 100644 index 00000000..e0965063 --- /dev/null +++ b/API_RESPONSE_STANDARD.md @@ -0,0 +1,85 @@ +# Standar Response API + +Proyek ini menggunakan format JSON standar untuk semua endpoint API. Kami telah menyediakan helper **Trait** untuk memudahkan implementasi agar konsisten di semua Controller. + +## Format Response JSON + +Setiap response API akan memiliki struktur berikut: + +```json +{ + "success": boolean, + "message": string, + "data": mixed +} +``` + +- **success**: `true` jika request berhasil, `false` jika gagal/error. +- **message**: Pesan deskriptif (misal: "Data berhasil diambil" atau "Ticket not found"). +- **data**: Payload utama (Object, Array, atau null). + +--- + +## Cara Penggunaan (Implementasi) + +Kami telah membuat Trait `App\Traits\ApiResponse` yang sudah di-load secara otomatis di **Base Controller**. + +### 1. Response Sukses (`successResponse`) + +Gunakan method `$this->successResponse($data, $message, $code)` di dalam controller. + +**Contoh (Index/List):** +```php +public function index() +{ + $projects = Project::all(); + + // Otomatis return JSON dengan success: true + return $this->successResponse(ProjectApiResource::collection($projects), 'List Data Project'); +} +``` + +**Contoh (Detail/Show):** +```php +public function show($id) +{ + $project = Project::find($id); + + return $this->successResponse(new ProjectApiResource($project), 'Detail Project'); +} +``` + +--- + +### 2. Response Error (`errorResponse`) + +Gunakan method `$this->errorResponse($message, $code, $data)` untuk mengembalikan error secara manual (bukan Exception). + +**Kapan digunakan?** +- Jika data by ID tidak ditemukan (404). +- Jika validasi logika bisnis gagal. +- Jika access denied (403). + +**Contoh (Data Not Found):** +```php +public function show($id) +{ + $ticket = Ticket::find($id); + + if (! $ticket) { + // Return success: false, status: 404 + return $this->errorResponse('Ticket not found', 404); + } + + return $this->successResponse($ticket, 'Detail Ticket'); +} +``` + +**Catatan Penting:** +Untuk endpoint **List/Index**, jika data kosong (0 record), **JANGAN** gunakan `errorResponse`. Tetap gunakan `successResponse` dengan data array kosong `[]`. + +--- + +## Lokasi File +- Trait: `app/Traits/ApiResponse.php` +- Base Controller: `app/Http/Controllers/Controller.php` diff --git a/app/Filament/Resources/ProjectResource.php b/app/Filament/Resources/ProjectResource.php index fccaffc4..f5cda92e 100644 --- a/app/Filament/Resources/ProjectResource.php +++ b/app/Filament/Resources/ProjectResource.php @@ -112,7 +112,8 @@ public static function form(Form $form): Form ->searchable() ->options([ 'kanban' => __('Kanban'), - 'scrum' => __('Scrum') + 'scrum' => __('Scrum'), + 'layanan' => 'Layanan', ]) ->reactive() ->default(fn() => 'kanban') diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php new file mode 100644 index 00000000..6159bf02 --- /dev/null +++ b/app/Http/Controllers/Api/ProjectController.php @@ -0,0 +1,23 @@ +orderBy('name', 'asc')->get(); + + return $this->successResponse(ProjectApiResource::collection($projects), 'List Data Master Project'); + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index a0a2a8a3..b65342ef 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -10,4 +10,5 @@ class Controller extends BaseController { use AuthorizesRequests, DispatchesJobs, ValidatesRequests; + use \App\Traits\ApiResponse; } diff --git a/app/Http/Resources/ProjectApiResource.php b/app/Http/Resources/ProjectApiResource.php new file mode 100644 index 00000000..b8c2b38f --- /dev/null +++ b/app/Http/Resources/ProjectApiResource.php @@ -0,0 +1,32 @@ + $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'ticket_prefix' => $this->ticket_prefix, + 'status_type' => $this->status_type, + 'type' => $this->type, + 'owner' => [ + 'id' => $this->owner_id, + 'name' => $this->owner?->name, + ], + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/app/Traits/ApiResponse.php b/app/Traits/ApiResponse.php new file mode 100644 index 00000000..517edd92 --- /dev/null +++ b/app/Traits/ApiResponse.php @@ -0,0 +1,42 @@ +json([ + 'success' => true, + 'message' => $message, + 'data' => $data, + ], $code); + } + + /** + * Error Response + * + * @param string $message + * @param int $code + * @param mixed $data + * @return \Illuminate\Http\JsonResponse + */ + public function errorResponse($message, $code = Response::HTTP_BAD_REQUEST, $data = null) + { + return response()->json([ + 'success' => false, + 'message' => $message, + 'data' => $data, + ], $code); + } +} diff --git a/routes/api.php b/routes/api.php index afaf194d..c525546d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -33,3 +33,4 @@ // }); Route::middleware('auth:sanctum')->get('/ticket/id/{id}', [\App\Http\Controllers\Api\TicketController::class, 'show']); +Route::middleware('auth:sanctum')->get('/projects', [\App\Http\Controllers\Api\ProjectController::class, 'index']); diff --git a/routes/web.php b/routes/web.php index 942ce20a..0435a9f0 100644 --- a/routes/web.php +++ b/routes/web.php @@ -56,5 +56,5 @@ Route::get('callback', [OidcAuthController::class, 'callback'])->name('callback'); }); -// Route::get('/kanban/{project}', Kanban::class)->name('filament.pages.kanban'); -// Route::get('/scrum/{project}', Scrum::class)->name('filament.pages.scrum'); +Route::get('/kanban/{project}', Kanban::class)->name('filament.pages.kanban'); +Route::get('/scrum/{project}', Scrum::class)->name('filament.pages.scrum');