Modern web development often relies on building decoupled applications where the frontend and backend are handled independently. Laravel 12, the latest version of the powerful PHP framework, offers robust tools for building RESTful APIs. On the frontend, frameworks like React and Vue dominate due to their dynamic, component-driven architecture.
In this guide, we’ll walk through how to build an API in Laravel 12 and consume it from a React or Vue frontend, making it a perfect stack for modern single-page applications (SPAs).
Let’s get started.
Step 1: Install Laravel 12
Start by creating a fresh Laravel 12 application using Composer. This ensures you’re working with the latest features and security patches.
composer create-project laravel/laravel laravel-api-app
cd laravel-api-app
Once installed, you can serve the app locally using:
php artisan serve
This will host your Laravel app at http://localhost:8000.
Step 2: Set Up the Database
Update your .env file to configure your database connection. Make sure your local database (e.g., MySQL or PostgreSQL) is running and you’ve created a new database.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_api
DB_USERNAME=root
DB_PASSWORD=
Then, run the migration command to create the default Laravel tables:
php artisan migrate
Step 3: Create a Model, Migration, and Controller
Let’s assume we’re working with a Post resource. Laravel can create the model, migration, and resource controller in one line:
php artisan make:model Post -mcr
-m
creates the migration file.-c
creates the controller.-r
makes the controller a resource controller.
Next, define the schema for the posts table in the newly created migration file in database/migrations/:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
Run the migration to create the table:
php artisan migrate
Step 4: Implement API Logic in Controller
Open the generated controller app/Http/Controllers/PostController.php and implement the CRUD methods using Eloquent ORM:
use App\Models\Post;
use Illuminate\Http\Request;
public function index()
{
return response()->json(Post::all());
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
]);
$post = Post::create($validated);
return response()->json($post, 201);
}
public function show($id)
{
$post = Post::findOrFail($id);
return response()->json($post);
}
public function update(Request $request, $id)
{
$post = Post::findOrFail($id);
$post->update($request->all());
return response()->json($post);
}
public function destroy($id)
{
Post::destroy($id);
return response()->json(['message' => 'Post deleted']);
}
Don’t forget to allow mass assignment in the model Post.php:
protected $fillable = ['title', 'content'];
Step 5: Define API Routes
Open routes/api.php and register the resource route for your Post controller:
use App\Http\Controllers\PostController;
Route::apiResource('posts', PostController::class);
Now, Laravel automatically maps all CRUD HTTP routes (GET, POST, PUT, DELETE) to the controller methods.
Step 6: Set Up API Authentication (Optional but Recommended)
If your frontend should only access protected routes, install Laravel Sanctum:
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Add Sanctum middleware in app/Http/Kernel.php under api group:
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
In your controller or routes, use auth:sanctum middleware for protected endpoints:
Route::middleware('auth:sanctum')->apiResource('posts', PostController::class);
Step 7: Set Up React or Vue Frontend
✅ React Setup
npx create-react-app laravel-react-app
cd laravel-react-app
npm install axios
Use Axios to make requests in a component:
import axios from 'axios';
import { useEffect, useState } from 'react';
function PostList() {
const [posts, setPosts] = useState([]);
useEffect(() => {
axios.get('http://localhost:8000/api/posts')
.then(response => setPosts(response.data))
.catch(error => console.error(error));
}, []);
return (
<div>
<h2>Posts</h2>
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
export default PostList;
✅ Vue Setup
npm init vue@latest
cd your-vue-project
npm install axios
In a Vue component:
<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';
const posts = ref([]);
onMounted(() => {
axios.get('http://localhost:8000/api/posts')
.then(response => posts.value = response.data)
.catch(error => console.error(error));
});
</script>
<template>
<div>
<h2>Posts</h2>
<ul>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>
Step 8: Test API with Frontend
Make sure your Laravel app (php artisan serve) and React/Vue app (npm run dev or npm start) are both running. If you face CORS issues, install Laravel CORS support:
composer require fruitcake/laravel-cors
Then publish the config file and allow your frontend origin in config/cors.php.
Bonus: Enable Cross-Origin Requests
Make sure your config/cors.php allows requests from http://localhost:3000 (React) or http://localhost:5173 (Vite/Vue):
'paths' => ['api/*'],
'allowed_origins' => ['http://localhost:3000', 'http://localhost:5173'],
Conclusion
By combining Laravel 12 as your backend API with React or Vue as your frontend, you unlock the potential of building fast, interactive, and maintainable applications.
Laravel’s API tooling and Eloquent ORM make backend development efficient, while frontend frameworks handle the user experience. Whether you’re building a blog, admin panel, or full SPA, this architecture is powerful, clean, and future-ready.
Read more