In this tutorials i will show you How to Upload and Download Files Using a Laravel API.
Uploading and downloading files through a Laravel API is a fundamental yet powerful feature for various applications. With some custom coding Laravel can easily support this feature, allowing you to upload images, PDF or any other files you wish.
How to Upload and Download Files Using a Laravel API
In this guide, we’ll walk through the steps to create a Laravel API that supports uploading, downloading and listing previously uploaded files. During the upload process we will store some basic file information in a table and show this information in the index response. You Can Learn How to Create Multilingual Website in Laravel
Let’s get started! How to Upload and Download Files Using a Laravel API
Step 1: Set Up Laravel Project
Begin by creating a new Laravel project using Composer:
composer create-project laravel/laravel file-api
Step 2: Configure Database
For simplicity I recommend using an SQLite Database on your local computer. If you’ve installed Laravel 11 or newer it will use SQLite out of the box. Otherwise you can use it by simply editing the .env
file in your Laravel root folder to:
.env
DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
Step 3: Create Migration
Run the following Artisan command to generate a “File
” model and a migration file:
php artisan make:model File -m
Step 4: Add Migration Code
Add the following code to the generated migration file to define the table’s columns in the up()
method and what happens when rolling back the migration in the down()
method
2024_04_19_171155_create_files_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('files', function (Blueprint $table) {
$table->id();
$table->string('original_name');
$table->string('generated_name');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('files');
}
};
Step 5: Run Migrations
Now we can actually create the table “files
” in our database by running:
php artisan migrate
Step 6: Add Model Code
Open the generated Model File.php
and add a $fillable
property to allow easy mass assignment of it’s values when we’ll be creating the record later:
app/Models/File.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class File extends Model
{
protected $fillable = [
'original_name',
'generated_name',
];
}
Step 7: Create Controller
Generate a FileController
class by running the following Artisan command:
php artisan make:controller FileController
Step 8: Add Controller code
Open the generated FileController.php
file and add the following methods to upload, download or show an index with all previously uploaded files:
app/Http/Controllers/FileUploadController.php
<?php
namespace App\Http\Controllers;
use App\Models\File;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class FileController extends Controller
{
// Receives a file upload
public function upload(Request $request): JsonResponse
{
$file = $request->file('file');
$fileName = Str::random(20) . '.' . $file->getClientOriginalExtension();
$file->storeAs('uploads', $fileName);
File::create([
'original_name' => $file->getClientOriginalName(),
'generated_name' => $fileName,
]);
return response()->json(['message' => 'File uploaded successfully']);
}
// Returns a list of previously uploaded files
public function index(): JsonResponse
{
$files = File::all();
return response()->json($files);
}
// Sends the requested file as a download, if found
public function download(File $file)
{
$filePath = storage_path("app/uploads/{$file->generated_name}");
if (file_exists($filePath)) {
return response()->download($filePath, $file->original_name);
} else {
abort(404, 'File not found');
}
}
}
Step 9: Configure Routes
Define routes to handle upload, download and index requests in routes/api.php
:
routes/api.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\FileController;
Route::get('/files', [FileController::class, 'index'])->name('files.index');
Route::post('/files/upload', [FileController::class, 'upload'])->name('files.upload');
Route::get('/files/{file}/download', [FileController::class, 'download'])->name('files.download');
These routes define the 3 endpoints our API provides for the outside world to use.
Let’s find out how to run and test our application in the next steps!
Step 10: Run the Application
Use the following artisan command to start the application:
php artisan serve
Now you can use our upload, download and show the index of files using a client of your choice by calling the endpoints accordingly:
- http://127.0.0.1:8000/api/files (via GET)
- http://127.0.0.1:8000/api/files/upload (via POST)
- http://127.0.0.1:8000/api/files/download (via GET)
This can be done by, for instance, another Laravel application or a tool like Postman. Personally I often use Postman to quickly verify an API works as expected.
In the next step I will show you how to setup Postman in order to test our example application.
Step 11: Test the API With Postman (Optional)
Now you can download Postman and use it to verify our API properly uploads, downloads and shows the index of files.
Let’s have a look at each of the requests involved.
- Making the “Upload” Request in Postman
Create a new request to http://127.0.0.1:8000/api/files/upload. Note that for this request the little dropdown next to the URL must be set to “POST”. In the “Body” tab switch to “form-data” and add a key with the name “file”, the little dropdown next to it must be changed from “File” to “Text”.
To upload a file use the “Value” column in the form-data. It opens a filepicker to select a file from your local disk. Now if you clock “Send” it will upload the file output a message, in the response “Body” in JSON format, saying “File uploaded successfully”:
- Making the “Index” Request in Postman
Create a new request to http://127.0.0.1:8000/api/files. Note that for this request the little dropdown next to the URL must be set to “GET”. In the “Body” tab keep everything empty. Now if you click “Send” you should receive a list of all previously uploaded files, in the response “Body” in JSON format:
- Making the “Download” Request in Postmanhttps://go.ezodn.com/charity/http/charity-ads.s3.amazonaws.com/charity_ads/1134/300×250.png×
Create a new request to http://127.0.0.1:8000/api/files/{{id}}/download. Note that for this request the little dropdown next to the URL must be set to “GET”. In the “Body” tab keep everything empty.
Note the the {{id}} part is a variable. You can edit this value by editing the collection “variables” . If you prefer, you can also use a hardcoded id you know exists in your files
table, for example: http://127.0.0.1:8000/api/files/1/download
Now if you click “Send” you should download the uploaded file or image and it will display it in the response “Body” part:
Important Caveat ! : Add “Accept” Header “application/json”
For each request you should add header line with key “Accept” and a value of “application/json”:
If you don’t add this Laravel will unexpectedly return a web 404 page instead of a proper API response with a list of error messages in JSON format.
Frequently Asked Questions
How can the API validate the upload request?
A production API should validate the upload request did actually send a file and that it is of the expected type and size.
app/Controllers/FileController.php
// Namespaces and imports ..
class FileController extends Controller {
public function upload(Request $request): JsonResponse
{
// Validate the incoming request
$request->validate([
// Accept only jpg,png images or a PDF with a maximum of 32 megabytes
'file' => 'required|file|mimes:jpeg,png,pdf|max:32768',
]);
$file = $request->file('file');
// Generate a unique file name
$fileName = Str::random(20) . '.' . $file->getClientOriginalExtension();
// Store the file in the 'uploads' directory
$file->storeAs('uploads', $fileName);
// Create a record in the database for the uploaded file
File::create([
'original_name' => $file->getClientOriginalName(),
'generated_name' => $fileName,
]);
// Return a success response
return response()->json(['message' => 'File uploaded successfully']);
}
// Rest of FileController class ..
}
How Can the API Upload Accept Multiple Files at Once?
In Postman (or any other client instead of sending your file form-data with key “file
” change the key to “file[]
” and alter the upload method to use a foreach loop.
The code would then look like:
app/Controllers/FileController.php
// Namespaces and imports ..
class FileController extends Controller {
public function upload(Request $request): JsonResponse
{
if ($request->hasFile('files')) {
foreach ($request->file('files') as $file) {
$fileName = Str::random(20) . '.' . $file->getClientOriginalExtension();
$file->storeAs('uploads', $fileName);
$uploadedFile = File::create([
'original_name' => $file->getClientOriginalName(),
'generated_name' => $fileName,
]);
$uploadedFiles[] = $uploadedFile;
}
}
return response()->json(['message' => 'Files uploaded successfully', 'files' => $uploadedFiles]);
}
// Rest of FileController class ..
}
In Postman you can then send, for example 4 files, like this:
How Can I Add Authentication to my Laravel API?
In most cases you can and should add authentication when running an API in production. Laravel provides several authentication methods out of the box, including token-based authentication using Laravel Passport or session-based authentication using Laravel Sanctum. Either of these 2 are a great fit for securing your file upload API.