# Laravel + Vue.js Monolith Backend Concepts ## Arsitektur Overview ``` ┌────────────────────────────────────────────────────────────┐ │ LARAVEL MONOLITH │ ├────────────────────────────────────────────────────────────┤ │ Frontend (SPA) │ Backend (API + Web) │ │ ───────────────── │ ────────────────── │ │ • Vue.js Components │ • Controllers │ │ • Vue Router │ • Models │ │ • Axios/HTTP Client │ • Migrations │ │ • State Management │ • Services │ │ │ • Jobs/Queues │ │ │ • Middleware │ └────────────────────────────────────────────────────────────┘ ``` ## 1. Hybrid Approach (Recommended) ### Konsep Kombinasi antara SPA (Vue.js) untuk user interface dan Laravel API untuk data handling. ### Routes Structure ```php // routes/web.php middleware('api')->group(function () { Route::get('/dashboard', [DashboardController::class, 'index']); Route::apiResource('posts', PostController::class); Route::apiResource('users', UserController::class); }); // Blade Routes (jika diperlukan) Route::get('/admin', function () { return view('admin.dashboard'); // Traditional Blade view }); // SPA Catch-all (harus paling bawah) Route::get('/{any}', function () { return view('spa'); // Vue.js SPA })->where('any', '^(?!api|admin).*$'); // Exclude api & admin routes ``` ### Controller Example ```php latest() ->paginate(10); return response()->json($posts); } public function store(Request $request): JsonResponse { $request->validate([ 'title' => 'required|max:255', 'content' => 'required', ]); $post = Post::create([ 'title' => $request->title, 'content' => $request->content, 'user_id' => auth()->id(), ]); return response()->json($post->load('author'), 201); } public function show(Post $post): JsonResponse { return response()->json($post->load('author')); } public function update(Request $request, Post $post): JsonResponse { $request->validate([ 'title' => 'required|max:255', 'content' => 'required', ]); $post->update($request->only(['title', 'content'])); return response()->json($post->load('author')); } public function destroy(Post $post): JsonResponse { $post->delete(); return response()->json(['message' => 'Post deleted successfully']); } } ``` ## 2. Frontend Integration ### Axios Setup ```javascript // resources/js/services/api.js import axios from 'axios' const api = axios.create({ baseURL: '/api', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', } }) // Add CSRF token for Laravel const token = document.head.querySelector('meta[name="csrf-token"]') if (token) { api.defaults.headers.common['X-CSRF-TOKEN'] = token.content } // Request interceptor api.interceptors.request.use((config) => { const auth = localStorage.getItem('auth_token') if (auth) { config.headers.Authorization = `Bearer ${auth}` } return config }) // Response interceptor api.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { // Handle unauthorized localStorage.removeItem('auth_token') window.location.href = '/login' } return Promise.reject(error) } ) export default api ``` ### Vue Service Example ```javascript // resources/js/services/postService.js import api from './api' export const postService = { // Get all posts async getPosts(page = 1) { const response = await api.get(`/posts?page=${page}`) return response.data }, // Get single post async getPost(id) { const response = await api.get(`/posts/${id}`) return response.data }, // Create post async createPost(postData) { const response = await api.post('/posts', postData) return response.data }, // Update post async updatePost(id, postData) { const response = await api.put(`/posts/${id}`, postData) return response.data }, // Delete post async deletePost(id) { const response = await api.delete(`/posts/${id}`) return response.data } } ``` ### Vue Component with API Integration ```vue Posts Create Post Loading posts... {{ post.title }} {{ post.content }} By {{ post.author.name }} Edit Delete {{ page }} {{ editingPost ? 'Edit Post' : 'Create Post' }} Title Content Cancel {{ editingPost ? 'Update' : 'Create' }} ``` ## 3. Authentication Integration ### Laravel Sanctum Setup ```bash # Install Sanctum composer require laravel/sanctum php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" php artisan migrate ``` ### Auth Controller ```php validate([ 'email' => 'required|email', 'password' => 'required', ]); $user = User::where('email', $request->email)->first(); if (!$user || !Hash::check($request->password, $user->password)) { throw ValidationException::withMessages([ 'email' => ['The provided credentials are incorrect.'], ]); } $token = $user->createToken('auth_token')->plainTextToken; return response()->json([ 'user' => $user, 'token' => $token, ]); } public function logout(Request $request) { $request->user()->currentAccessToken()->delete(); return response()->json(['message' => 'Logged out successfully']); } public function me(Request $request) { return response()->json($request->user()); } } ``` ## 4. Database Structure ### Migration Example ```php id(); $table->string('title'); $table->text('content'); $table->string('slug')->unique(); $table->foreignId('user_id')->constrained()->onDelete('cascade'); $table->boolean('published')->default(false); $table->timestamp('published_at')->nullable(); $table->timestamps(); $table->index(['published', 'published_at']); }); } public function down() { Schema::dropIfExists('posts'); } }; ``` ### Model with Relationships ```php 'boolean', 'published_at' => 'datetime', ]; public function author(): BelongsTo { return $this->belongsTo(User::class, 'user_id'); } public function getRouteKeyName() { return 'slug'; } } ``` ## 5. Service Layer Pattern ### Service Class ```php where('published', true) ->latest('published_at') ->paginate($perPage); } public function createPost(array $data): Post { $data['slug'] = Str::slug($data['title']); $data['user_id'] = auth()->id(); return Post::create($data); } public function updatePost(Post $post, array $data): Post { if (isset($data['title'])) { $data['slug'] = Str::slug($data['title']); } $post->update($data); return $post->fresh(); } public function deletePost(Post $post): bool { return $post->delete(); } } ``` ## 6. Middleware untuk API ### Custom API Middleware ```php expectsJson()) { $data = $response->getData(); return response()->json([ 'success' => $response->status() < 400, 'data' => $data, 'message' => $response->status() < 400 ? 'Success' : 'Error', 'status_code' => $response->status(), ], $response->status()); } return $response; } } ``` ## Key Benefits Monolith ✅ **Single Deployment** - Satu aplikasi, satu deploy ✅ **Shared Authentication** - Session/token bersama ✅ **Database Consistency** - Satu database, konsisten ✅ **Easier Development** - Setup dan maintenance lebih mudah ✅ **Performance** - Tidak ada network latency antar service ✅ **CSRF Protection** - Built-in Laravel CSRF ✅ **File Sharing** - Storage dan assets bersama ## Best Practices 1. **API Versioning** - Gunakan `/api/v1/` prefix 2. **Resource Controllers** - Gunakan `apiResource()` untuk CRUD 3. **Service Layer** - Pisahkan business logic dari controller 4. **Validation** - Gunakan Form Requests untuk validasi complex 5. **Caching** - Implement caching untuk data yang sering diakses 6. **Queue Jobs** - Untuk operasi yang memakan waktu 7. **Event/Listeners** - Untuk decoupling business logic Konsep ini memberikan fleksibilitas tinggi dengan maintenance yang relatif mudah!
{{ post.content }}