In this section we will perform crud operations using laravel 9 rest api with vue 3 composition api. create will laravel backend api crud with vue 3 frontend crud using vue composition api.
Laravel 9 Backend Api Connect with Vue 3 Using Axios Example
Create Laravel 9 Rest Api CRUD
Install fresh laravel app and connect to database.
composer create-project laravel/laravel laravel-api
Create Post Api Model Migration Controller and Route
Run below command to create model and migration.
php artisan make:model Post -m
create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
migrate table
php artisan migrate
app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'content'
];
}
Create Post Api Controller
run below command to create pots api controller.
php artisan make:controller Api/PostController --model=Post
Add Logic Post Api crud in PostController.
app/Http/Controllers/Api/PostController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$posts = Post::latest()->get();
return response()->json([
'success' => true,
'message' => 'List data post',
'data' => $posts
], 200);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'content' => 'required'
]);
$posts = Post::create([
'title' => $request->title,
'content' => $request->content
]);
return response()->json([
'success' => true,
'message' => 'Post created',
'data' => $posts
], 201);
}
/**
* Display the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function show(Post $post)
{
return response()->json([
'success' => true,
'message' => 'Detail data post',
'data' => $post
], 200);
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function edit(Post $post)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Post $post)
{
$request->validate([
'title' => 'required|string|max:255',
'content' => 'required'
]);
$post = Post::find($post->id);
if ($post) {
$post->update([
'title' => $request->title,
'content' => $request->content
]);
return response()->json([
'success' => true,
'message' => 'Post updated',
'data' => $post
], 200);
}
return response()->json([
'success' => false,
'message' => 'Post not found'
], 404);
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function destroy(Post $post)
{
if ($post) {
$post->delete();
return response()->json([
'success' => true,
'message' => 'Post deleted'
], 200);
}
return response()->json([
'success' => false,
'message' => 'Post not found'
], 404);
}
}
routes/api.php
Route::apiResource('posts',PostController::class);
Run the server
php artisan serve
Vue 3 Composition Api CRUD Using Laravel REST API
Create vue 3 project.
npm init [email protected]
Select your requirements.
Vue.js - The Progressive JavaScript Framework
✔ Project name: … frontend
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
Scaffolding project in /vue-project/frontend...
Done. Now run:
cd frontend
npm install
npm run dev
Install axios In Vue 3
Run below command to install vue-axios
npm i vue-axios
Install Tailwind CSS in Vue 3
How to Install Tailwind CSS in Vue 3
or
Set Axios Path in vue 3
Setup Api path in main.js using axios.
src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:8000/api/';
const app = createApp(App)
app.use(router)
app.mount('#app')
Create Post (Index,Create,Edit) routes file
src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import Posts from '../views/posts/Index.vue'
import PostCreate from '../views/posts/Create.vue'
import PostEdit from '../views/posts/Edit.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/posts',
name: 'posts',
component: Posts
},
{
path: '/posts/create',
name: 'posts.create',
component: PostCreate
},
{
path: '/posts/:id',
name: 'posts.edit',
component: PostEdit
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue')
}
]
})
export default router
Perform CRUD Operations Vue 3 Composition Api using Laravel Backend API
views/posts/Create.vue
<template>
<div class="flex items-center justify-center h-screen">
<div class="">
<span v-if="validation.message" class="px-2 py-2 mb-4 text-red-600 rounded shadow">
{{ validation.message }}
</span>
<form @submit.prevent="submit">
<div>
<label for="title">Title</label>
<input
type="text"
name="title"
v-model="post.title"
class="w-full px-4 py-2 border border-gray-300 outline-none"
/>
</div>
<div>
<label for="content">Content</label>
<textarea
name="content"
v-model="post.content"
class="w-full px-4 py-2 border border-gray-300 outline-none"
cols="10"
rows="4"
></textarea>
</div>
<button class="px-6 py-2 text-white bg-blue-600" type="submit">
Button
</button>
</form>
</div>
</div>
</template>
<script>
import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import axios from 'axios';
export default {
setup() {
const post = reactive({
title: '',
content: '',
});
const validation = ref([]);
const router = useRouter();
function submit() {
let title = post.title;
let content = post.content;
axios
.post('http://localhost:8000/api/posts', {
title: title,
content: content,
})
.then(() => {
router.push({
name: 'posts',
});
})
.catch((error) => {
validation.value = error.response.data;
});
}
return {
post,
validation,
router,
submit,
};
},
};
</script>
views/posts/Index.vue
<template>
<main class="container flex items-center justify-center h-screen mx-auto">
<div class="flex flex-col">
<div class="overflow-x-auto">
<div class="p-1.5 w-full inline-block align-middle">
<RouterLink to="/posts/create" class="p-2 text-white bg-blue-600"
>Create</RouterLink
>
<div class="mt-3 overflow-hidden border rounded-lg">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th
scope="col"
class="px-6 py-3 text-xs font-bold text-left text-gray-500 uppercase"
>
ID
</th>
<th
scope="col"
class="px-6 py-3 text-xs font-bold text-left text-gray-500 uppercase"
>
Title
</th>
<th
scope="col"
class="px-6 py-3 text-xs font-bold text-left text-gray-500 uppercase"
>
Edit
</th>
<th
scope="col"
class="px-6 py-3 text-xs font-bold text-center text-gray-500 uppercase"
>
Delete
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tr v-for="post in posts" :key="post.id">
<td
class="px-6 py-4 text-sm font-medium text-gray-800 whitespace-nowrap"
>
{{ post.id }}
</td>
<td class="px-6 py-4 text-sm text-gray-800 whitespace-nowrap">
{{ post.title }}
</td>
<td class="px-6 py-4 text-sm text-gray-800 whitespace-nowrap">
<RouterLink
:to="{ name: 'posts.edit', params: { id: post.id } }"
class="text-green-500"
>EDIT</RouterLink
>
</td>
<td class="px-6 py-4 text-sm text-gray-800 whitespace-nowrap">
<button
@click.prevent="postDelete(post.id, index)"
class="text-red-600"
>
DELETE
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</main>
</template>
<script>
import axios from 'axios';
import { onMounted, ref } from 'vue';
export default {
setup() {
let posts = ref([]);
onMounted(() => {
// fetch api from laravel backend
axios
.get('http://localhost:8000/api/posts')
.then((res) => {
posts.value = res.data.data;
})
.catch((error) => {
console.log(error.res.data);
});
});
function postDelete(id, index) {
axios
.delete(`http://localhost:8000/api/posts/${id}`)
.then(() => {
posts.value.splice(index, 1);
})
.catch((error) => {
console.log(error.response.data);
});
}
return {
posts,
postDelete,
};
},
};
</script>
views/posts/Edit.vue
<template>
<div class="flex items-center justify-center h-screen">
<div class="">
<span
v-if="validation.message"
class="px-2 py-2 mb-4 text-red-600 rounded shadow"
>
{{ validation.message }}
</span>
<form @submit.prevent="submit">
<div>
<label for="title">Title</label>
<input
type="text"
name="title"
v-model="post.title"
class="w-full px-4 py-2 border border-gray-300 outline-none"
/>
</div>
<div>
<label for="content">Content</label>
<textarea
name="content"
v-model="post.content"
class="w-full px-4 py-2 border border-gray-300 outline-none"
cols="10"
rows="4"
></textarea>
</div>
<button class="px-6 py-2 text-white bg-blue-600" type="submit">
Button
</button>
</form>
</div>
</div>
</template>
<script>
import { reactive, ref, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import axios from 'axios';
export default {
setup() {
const post = reactive({
title: '',
content: '',
});
const validation = ref([]);
const router = useRouter();
const route = useRoute();
onMounted(() => {
// fetch api from laravel backend
axios
.get(`http://localhost:8000/api/posts/${route.params.id}`)
.then((response) => {
post.title = response.data.data.title;
post.content = response.data.data.content;
})
.catch((error) => {
console.log(error.response.data);
});
});
function submit() {
let title = post.title;
let content = post.content;
axios
.put(`http://localhost:8000/api/posts/${route.params.id}`, {
title: title,
content: content,
})
.then(() => {
router.push({
name: 'posts',
});
})
.catch((error) => {
validation.value = error.response.data;
});
}
return {
post,
validation,
router,
submit,
};
},
};
</script>
Run vue server.
npm run dev
Read Also
Laravel 9 Add Simple Sidebar with Tailwind CSS Example
How to Use Carousel Slider in Laravel 9 Example
Laravel 9 Posts with Tags Many to Many Relationships Example
Laravel 9 Insert Category in Posts CRUD Example
How to Use Ckeditor 5 in Laravel 9 Vite with Tailwind CSS
Laravel 9 Simple Image Upload in Ckeditor 5 Example
Laravel 9 Flash Message Timeout and Hide Message Example
Install & Setup Markdown Editor in Laravel 9
Nuxt 3 Data Fetching Using Laravel 9 Api Example
Laravel 9 Image Upload with Preview using Tailwind CSS & Alpine JS
Laravel 9 with Tailwind CSS Form Validation Example
Laravel 9 Backend Api Connect with Vue 3 Using Axios Example
Laravel 9 Authentication with Next js Example
Laravel 9 Sanctum Authentication with Nuxt JS Example
Laravel 9 Simple Search with Pagination Example
Laravel 9 Install Setup TALL(Tailwind, Alpinejs, Livewire) Admin Panel
How to Fix and Clean Code Style in laravel 9
Laravel 9 Image File Upload Example
3 Way to Create Slug in Laravel 9 without Package
How to Add Dark Mode in Laravel 9 with Tailwind CSS