Handling File Uploads in REST APIs: A Laravel Guide
Master secure file uploads in Laravel REST APIs. Learn to validate binary data, use the Filesystem abstraction, and associate files with your Eloquent models.
Previously in this course, we explored Handling API Validation and Form Requests. While that lesson focused on standard request payloads, today we’re moving into binary data. We’ll cover how to securely accept, store, and link files to your project board entities.
From First Principles: The Filesystem Abstraction
In a production environment, you should never hardcode file paths or manipulate the local disk directly. Laravel provides the Illuminate\Support\Facades\Storage facade, which acts as a filesystem abstraction layer. Whether you are storing files on your local server, an S3 bucket, or an SFTP server, your code remains identical.
When building a REST API, files arrive as multipart/form-data. Because these requests are inherently larger and potentially malicious, we treat them with higher scrutiny than standard JSON payloads.
Validating and Storing Files
Before storing a file, validation is non-negotiable. You must enforce constraints on file size and MIME types to prevent users from uploading executable scripts or exhausting your server’s disk space.
Building upon our project board, let’s add a feature to attach files to tasks. First, create a StoreTaskAttachmentRequest:
PHP#6A9955">// app/Http/Requests/StoreTaskAttachmentRequest.php public function rules(): array { return [ 'attachment' => [ 'required', 'file', 'mimes:jpg,png,pdf', 'max:2048' #6A9955">// 2MB limit ], ]; }
Once validated, we use the store method. This method handles filename hashing (to prevent collisions) and returns the relative path to the file.
PHP#6A9955">// Inside your TaskService public function addAttachment(Task $task, UploadedFile $file): Attachment { #6A9955">// Store in the 'attachments' directory on the 'public' disk $path = $file->store('attachments', 'public'); return $task->attachments()->create([ 'path' => $path, 'original_name' => $file->getClientOriginalName(), 'mime_type' => $file->getClientMimeType(), ]); }
Associating Files with Models
In a relational database, you shouldn't store the file itself in a BLOB column. Instead, store the metadata (path, original name, size) in a dedicated attachments table.
- The Migration: Create a migration with
task_id,path, andoriginal_name. - The Relationship: Define a
hasManyrelationship on yourTaskmodel. - The Storage: Use the
publicdisk if the files need to be accessible via URL, or thelocaldisk for private, server-only files.
Hands-on Exercise: Secure Attachment Upload
- Create a migration for an
attachmentstable with atask_idforeign key and apathstring column. - Generate a
TaskAttachmentControllerand inject yourTaskService. - Implement an endpoint
POST /tasks/{task}/attachments. - Use the
storemethod to save the file and persist the metadata to the database. - Verify that the file is stored in
storage/app/public/attachments.
Common Pitfalls
- Ignoring File Permissions: Ensure your
storage/directory is writable by the web server (usuallywww-data). - Trusting Client-Provided Names: Never use the filename provided by the user directly in your database or filesystem. Laravel's
store()method automatically generates a unique hash, which is exactly what you want to prevent directory traversal attacks. - Hardcoding Local Paths: Always use
Storage::url($path)to generate links. If you switch to S3 later, this method will automatically generate the correct signed URL without you changing a single line of business logic. - Memory Exhaustion: If your users upload massive files, ensure your
php.ini(upload_max_filesizeandpost_max_size) matches your validation rules.
Recap
We’ve moved from simple JSON requests to handling binary data securely. By utilizing Laravel’s Storage facade, we've decoupled our application from the underlying storage mechanism. We ensure security through strict FormRequest validation and maintain database integrity by storing metadata rather than raw binary data.
Up next: We will implement Job Chaining and Batching to handle post-processing (like image resizing) for these file uploads in the background.
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app — built with FilamentPHP so you can manage everything without touching the database.