Mobile File Upload API (Flutter ↔ Laravel)
Dokumen ini menjelaskan alur kerja (workflow) untuk mengunggah file dari aplikasi Mobile (Flutter) ke server Laravel menggunakan Pre-Signed URL serta cara menghubungkannya dengan model utama.
Perbandingan Parameter Request
Untuk mendukung fitur "Upload Baru" sekaligus "Pilih dari Gallery (Media Lama)", API menggunakan dua parameter berbeda:
avatar_upload_id: Digunakan saat Flutter selesai melakukan upload file baru melalui jalur Pre-signed URL. Berisi UUID dari tabeltemporary_uploads.avatar_media_id: Digunakan saat user memilih foto yang sudah pernah diunggah sebelumnya (Gallery). Berisi ID dari tabelcurator_media.
Alur Kerja (Step-by-Step)
1. Tahap Persiapan (Prepare)
Flutter meminta URL upload.
- Endpoint:
POST /api/v1/uploads/prepare - Respons: Mendapatkan
upload_iddanupload_url.
2. Tahap Unggah Fisik (Direct Upload)
Flutter melakukan PUT binary file ke upload_url.
3. Tahap Penandaan Selesai (Mark Uploaded)
Flutter memanggil POST /api/v1/uploads/{upload_id}/mark-uploaded.
4. Tahap Finalisasi (Penyimpanan ke Model)
Saat menyimpan data (misal: Update Profile), Flutter mengirimkan salah satu ID di atas.
Contoh Payload Request:
{
"name": "Budi",
"avatar_upload_id": "9b1e... (UUID dari tahap 1)"
}
Implementasi Backend (Action Pattern)
Sesuai dengan Action Pattern di proyek ini, Action tidak boleh menerima instance Request. Controller bertugas mengekstrak data dari request dan meneruskannya ke Action dalam bentuk array $data.
Logika di Controller (AuthController.php)
public function update(UpdateProfileRequest $request, UpdateProfileAction $action)
{
// Controller mengekstrak data dari request
$data = $request->validated();
// Jalankan action dengan array data
$user = $action->handle(auth()->user(), $data);
return new UserResource($user);
}
Logika di Action (UpdateProfileAction.php)
Action akan mendeteksi apakah ada upload_id yang perlu difinalisasi menjadi Media Curator.
public function handle(User $user, array $data): User
{
// 1. Cek apakah ada upload baru yang harus difinalisasi
if (!empty($data['avatar_upload_id'])) {
// Panggil Action lain untuk konversi TemporaryUpload -> Curator Media
$media = $this->finalizeUploadAction->handle([
'upload_id' => $data['avatar_upload_id'],
'user_id' => $user->id,
]);
$data['avatar_id'] = $media->id;
}
// 2. Jika user memilih dari media yang sudah ada
elseif (!empty($data['avatar_media_id'])) {
// Validasi kepemilikan media bisa dilakukan di FormRequest atau di sini
$data['avatar_id'] = $data['avatar_media_id'];
}
// 3. Update model user dengan avatar_id (ID Curator) yang sudah fix
$user->update(Arr::only($data, ['name', 'avatar_id', 'locale', 'timezone']));
return $user;
}
Keuntungan Bagi Developer
- CLI Ready: Action ini bisa dipanggil dari Command Line atau Seeder dengan mudah karena hanya butuh array.
- Flexible UI: User bisa upload foto baru atau sekadar mengganti avatar dengan foto lama (seperti fitur di Facebook/Google).
- Decoupled: Logika konvensional file biner tidak mengotori logika update profile user.