Laravel 11 + Vue.js 3 CRUD with Composition API

Tutorial last revisioned on March 15, 2024 with Laravel 11 and Vue.js 3

There are quite a lot of articles/videos on Laravel + Vue CRUD, but not enough is published on the newest Vue.js 3 version, using the new Composition API. So, with this step-by-step detailed article, let's fill in that gap, building a simple Company management form.

Notice: the link to the final repository is at the end of the article.


Install Laravel and Laravel Breeze

We start from the very beginning, by installing a fresh Laravel project, and a Laravel Breeze starter kit:

laravel new project
cd project
// editing .env file here
composer install
php artisan migrate
composer require laravel/breeze --dev
php artisan breeze:install blade

By this point, we should have a default Laravel Breeze with Tailwind CSS design, and Login/Register functionality:

Creating Model and API CRUD

We will manage one table called Companies, with four text fields: name, email, address, website.

So, we create the model, and automatically create migrations with -m:

php artisan make:model Company -m

This is the DB structure: database/migrations/xxxxx_create_companies_table.php:

class CreateCompaniesTable extends Migration
{
public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->string('address')->nullable();
$table->string('website')->nullable();
$table->timestamps();
});
}
 
public function down()
{
Schema::dropIfExists('companies');
}
}

Then, of course, we run the migration:

php artisan migrate

In the app/Models/Company.php model, we make all fields fillable:

class Company extends Model
{
use HasFactory;
 
protected $fillable = ['name', 'email', 'address', 'website'];
}

Next, we create a Controller, with a few flags to generate exactly what we need:

php artisan make:controller Api/CompanyController --resource --api --model=Company

Personally, I like to use API Resources to transform the data. Although in this project, we won't make any transformations, I still have a habit of generating them:

php artisan make:resource CompanyResource

And, inside of app/Http/Resources/CompanyResource.php, there's this default code:

class CompanyResource extends JsonResource
{
public function toArray($request)
{
return parent::toArray($request);
}
}

Next, for validation, we generate a FormRequest class:

php artisan make:request CompanyRequest

In this case, I will re-use the same validation rules for both store/update functions, so this is the content of app/Http/Requests/CompanyRequest.php:

class CompanyRequest extends FormRequest
{
public function authorize()
{
return true;
}
 
public function rules()
{
return [
'name' => ['required', 'string'],
'email' => ['required', 'email'],
'address' => ['nullable', 'string'],
'website' => ['nullable', 'url'],
];
}
}

We use those API Resource and Form Request classes inside of our app/Http/Controllers/API/CompanyController.php, which has this code:

namespace App\Http\Controllers\Api;
 
use App\Http\Controllers\Controller;
use App\Http\Requests\CompanyRequest;
use App\Http\Resources\CompanyResource;
use App\Models\Company;
 
class CompanyController extends Controller
{
public function index()
{
return CompanyResource::collection(Company::all());
}
 
public function store(CompanyRequest $request)
{
$company = Company::create($request->validated());
 
return new CompanyResource($company);
}
 
public function show(Company $company)
{
return new CompanyResource($company);
}
 
public function update(CompanyRequest $request, Company $company)
{
$company->update($request->validated());
 
return new CompanyResource($company);
}
 
public function destroy(Company $company)
{
$company->delete();
 
return response()->noContent();
}
}

And, we tie it all together to call that Controller from the routes/api.php:

use App\Http\Controllers\Api\CompanyController;
 
// ...
 
Route::apiResource('companies', CompanyController::class);

In this simple project, we won't use any Middleware, the routes are public.

So, at this point, we have an API ready, and if we enter some company manually in the DB, here's what we get via Postman:


Installing Vue and "Hello World"

Now, we get to the front-end. We install Vue.js, Vue Router and Vue Loader:

npm install vue@latest vue-router@4

As of Monday, February 7, 2022 Vue 3 is the default version. So you can install Vue 3 using @latest which versions is what we want in this article to use Composition API.

Next, we need to tell Vite to use vue when compiling. First, install vite vue plugin.

npm install --save-dev @vitejs/plugin-vue

Then import Vue plugin import vue from '@vitejs/plugin-vue'; in vite.config.js. Then add Vue to plugins array.

Before:

export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true,
}),
],
});

After...

The full tutorial [22 mins, 4351 words] is only for Premium Members

Login Or Become a Premium Member for $129/year or $29/month
What else you will get:
  • 68 courses (1188 lessons, total 43 h 18 min)
  • 90 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent New Courses