Skip to content

API / SPA Starter Kit

About

This starter-kit repository provides a Vue SPA (Single Page Application) that connects to a Laravel API backend, authenticated with Laravel Sanctum. The project provides the same authentication and profile pages/features as the Inertia starter-kit.

Vue SPA Setup

Clone from source repository:

bash
git clone https://github.com/connorabbas/laravel-api-primevue-starter-kit.git your-project-name
bash
git clone git@github.com:connorabbas/laravel-api-primevue-starter-kit.git your-project-name

Alternatively:

Laravel API Setup

  1. Create a new Laravel application

  2. Install Laravel Breeze using the API Stack option

  3. Setup necessary .env configuration values in the Laravel API project

    bash
    # Example implementation
    # Remember, your SPA and API must share the same top-level domain
    APP_URL=http://api.vue-spa.localhost # Match this value with VITE_API_BASE_URL in the Vue app
    FRONTEND_URL=http://vue-spa.localhost # Add app.frontend_url config entry as needed
    SANCTUM_STATEFUL_DOMAINS="vue-spa.localhost"
    SESSION_DOMAIN="vue-spa.localhost"
  4. Create controllers

    bash
    php artisan make:controller ProfileController
    bash
    php artisan make:controller Auth/PasswordController
  5. Copy Controller code

    php
    <?php
    
    namespace App\Http\Controllers;
    
    use App\Models\User;
    use Illuminate\Http\Request;
    use Illuminate\Http\Response;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Validation\Rule;
    use Illuminate\View\View;
    
    class ProfileController extends Controller
    {
        /**
        * Update the user's profile information.
        */
        public function update(Request $request): Response
        {
            $validated = $request->validate([
                'name' => ['required', 'string', 'max:255'],
                'email' => [
                    'required',
                    'string',
                    'lowercase',
                    'email',
                    'max:255',
                    Rule::unique(User::class)->ignore($request->user()->id),
                ],
            ]);
    
            $request->user()->fill($validated);
    
            if ($request->user()->isDirty('email')) {
                $request->user()->email_verified_at = null;
            }
    
            $request->user()->save();
    
            return response()->noContent();
        }
    
        /**
        * Delete the user's account.
        */
        public function destroy(Request $request): Response
        {
            $request->validate([
                'password' => ['required', 'current_password'],
            ]);
    
            $user = $request->user();
    
            Auth::logout();
    
            $user->delete();
    
            $request->session()->invalidate();
            $request->session()->regenerateToken();
    
            return response()->noContent();
        }
    }
    php
    <?php
    
    namespace App\Http\Controllers\Auth;
    
    use App\Http\Controllers\Controller;
    use Illuminate\Http\Request;
    use Illuminate\Http\Response;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Validation\Rules\Password;
    
    class PasswordController extends Controller
    {
        /**
        * Update the user's password.
        */
        public function update(Request $request): Response
        {
            $validated = $request->validate([
                'current_password' => ['required', 'current_password'],
                'password' => ['required', Password::defaults(), 'confirmed'],
            ]);
    
            $request->user()->update([
                'password' => Hash::make($validated['password']),
            ]);
    
            if ($request->session()->has('password_hash_web')) {
                $user = Auth::user();
                $request->session()->forget('password_hash_web');
                Auth::login($user);
            }
    
            return response()->noContent();
        }
    }
  6. Setup routes

    php
    Route::controller(App\Http\Controllers\ProfileController::class)
        ->middleware('auth')
        ->group(function () {
            Route::patch('/profile', 'update')->name('profile.update');
            Route::delete('/profile', 'destroy')->name('profile.destroy');
        });
    
    Route::put('password', [App\Http\Controllers\Auth\PasswordController::class, 'update'])
        ->middleware('auth')
        ->name('password.update');