Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

Subscribe to the newsletter

Get new articles and course lessons delivered to your inbox. No spam, unsubscribe anytime.

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 22 of the Intermediate Laravel: Real-World Application Patterns course
LaravelJune 26, 20263 min read

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.

LaravelREST APIStorageFilesystemValidationphpbackend

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.

  1. The Migration: Create a migration with task_id, path, and original_name.
  2. The Relationship: Define a hasMany relationship on your Task model.
  3. The Storage: Use the public disk if the files need to be accessible via URL, or the local disk for private, server-only files.

Hands-on Exercise: Secure Attachment Upload

  1. Create a migration for an attachments table with a task_id foreign key and a path string column.
  2. Generate a TaskAttachmentController and inject your TaskService.
  3. Implement an endpoint POST /tasks/{task}/attachments.
  4. Use the store method to save the file and persist the metadata to the database.
  5. 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 (usually www-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_filesize and post_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.

Previous lessonAdvanced Request Filtering and SortingNext lesson Real-time Notifications with Broadcasting
Back to Blog

Similar Posts

LaravelJune 28, 20263 min read

Handling Large File Uploads: Streaming to S3 & Async Processing

Master scalable file uploads in Laravel. Learn to stream directly to S3 and process heavy files asynchronously to keep your application fast and memory-efficient.

Read more
LaravelJune 28, 20263 min read

Handling Webhooks Securely: Validation and Queueing in Laravel

Learn to build production-ready integrations by validating webhook signatures and offloading processing to queues to ensure security and system reliability.

Part of the course

Intermediate Laravel: Real-World Application Patterns

intermediate · Lesson 22 of 58

  1. 1

    Architecting for Maintainability

    3 min
  2. 2

    Implementing the Service Layer

    3 min
  3. 3

    Repository Pattern Fundamentals

    3 min
Read more
LaravelJune 28, 20264 min read

Advanced Database Migration Strategies for Laravel

Master non-breaking migrations and safe rollback procedures. Learn the expand-and-contract pattern to evolve your database schema without production downtime.

Read more
  • 4

    Project Board Domain Modeling

    3 min
  • 5

    Advanced Eloquent Scopes and Accessors

    4 min
  • 6

    Service-Oriented Task Management

    3 min
  • 7

    REST API Fundamentals with Sanctum

    3 min
  • 8

    Resource Controllers and API Responses

    3 min
  • 9

    Handling API Validation and Form Requests

    3 min
  • 10

    Implementing Middleware for API Security

    4 min
  • 11

    Database Transactions for Data Integrity

    3 min
  • 12

    Error Handling and Global Exceptions

    3 min
  • 13

    Introduction to Laravel Events and Listeners

    3 min
  • 14

    Asynchronous Processing with Queues

    4 min
  • 15

    Job Chaining and Batching

    3 min
  • 16

    Feature Testing Fundamentals

    4 min
  • 17

    Mocking Services and Repositories in Tests

    3 min
  • 18

    Testing Events and Jobs

    3 min
  • 19

    Database Factories and Seeding

    3 min
  • 20

    API Versioning Strategies

    4 min
  • 21

    Advanced Request Filtering and Sorting

    3 min
  • 22

    Handling File Uploads in REST APIs

    3 min
  • 23

    Real-time Notifications with Broadcasting

    3 min
  • 24

    Using Observers for Model Lifecycle Hooks

    3 min
  • 25

    Implementing Policies for Authorization

    3 min
  • 26

    Customizing Authentication Guards

    3 min
  • 27

    Rate Limiting API Endpoints

    4 min
  • 28

    Eloquent Performance Optimization

    4 min
  • 29

    Caching Strategies for Performance

    4 min
  • 30

    Using Traits for Code Reuse

    3 min
  • 31

    Advanced Dependency Injection with Service Providers

    3 min
  • 32

    Command Line Tools with Artisan

    3 min
  • 33

    Scheduled Tasks and Cron Jobs

    3 min
  • 34

    Integrating Third-Party Services

    3 min
  • 35

    Handling Webhooks

    3 min
  • 36

    Logging and Monitoring

    3 min
  • 37

    Database Migrations Best Practices

    3 min
  • 38

    Advanced Testing: Integration Tests

    4 min
  • 39

    Testing API Authentication

    4 min
  • 40

    Code Quality and Static Analysis

    3 min
  • 41

    Project Structure for Large Applications

    3 min
  • 42

    Environment and Configuration Management

    3 min
  • 43

    Deploying Laravel Applications

    4 min
  • 44

    Database Indexing Strategies

    4 min
  • 45

    Using Value Objects

    4 min
  • 46

    Strategy Pattern for Business Rules

    3 min
  • 47

    Advanced Queue Monitoring

    3 min
  • 48

    Building a Search API

    3 min
  • 49

    Handling Concurrency and Race Conditions

    4 min
  • 50

    API Documentation with OpenAPI

    3 min
  • 51

    Testing with Test Doubles

    3 min
  • 52

    Implementing Multi-Tenancy

    4 min
  • 53

    Refactoring Legacy Code

    4 min
  • 54

    Using Middleware for Feature Flags

    3 min
  • 55

    Building Reusable Packages

    4 min
  • 56

    Performance Profiling

    3 min
  • 57

    Secure API Design

    3 min
  • 58

    Event Sourcing Concepts

    4 min
  • View full course