LATEST >>

Welcome Here And Thanks For Visiting. Like Us On Facebook...

EXEIdeas – Let's Your Mind Rock » PHP Codes » How To Create A Basic Backend API Boilerplate Using PHP Laravel?

How To Create A Basic Backend API Boilerplate Using PHP Laravel?

How-To-Create-A-Basic-Backend-API-Boilerplate-Using-PHP-Laravel

Building a backend API is a fundamental skill for modern web developers, and Laravel provides an elegant framework to create robust APIs quickly. In this comprehensive guide, we’ll walk through creating a complete Laravel API boilerplate that includes authentication, database migrations, route handling, and proper response formatting.

“Laravel’s elegant syntax and powerful features make it one of the best PHP frameworks for API development, combining simplicity with enterprise-ready capabilities.”

Prerequisites For Laravel API Development

Before diving into our Laravel API boilerplate, ensure you have the following setup:

  • PHP 8.0 or higher installed
  • Composer for dependency management
  • A database system (MySQL, PostgreSQL, or SQLite)
  • Basic understanding of RESTful API concepts

Setting Up Your Laravel Project

Let’s begin by creating a fresh Laravel installation. Open your terminal and run:

composer create-project laravel/laravel api-boilerplate

Navigate to your project directory:

cd api-boilerplate

Configuring Your Environment

Edit the .env file to set up your database connection:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_api
DB_USERNAME=root
DB_PASSWORD=

Understanding The Laravel Directory Structure

Before we proceed, it’s crucial to understand key directories in our Laravel API project:

  • app/Http/Controllers – Houses our API controllers
  • routes/api.php – Contains our API routes
  • database/migrations – Stores database migration files
  • app/Models – Contains our Eloquent models

Creating API Routes

Laravel provides a dedicated routes file for APIs. Open routes/api.php and let’s define our basic endpoints:

use App\Http\Controllers\API\AuthController;
use App\Http\Controllers\API\PostController;

Route::prefix('v1')->group(function() {
    // Authentication routes
    Route::post('register', [AuthController::class, 'register']);
    Route::post('login', [AuthController::class, 'login']);
    
    // Protected routes
    Route::middleware('auth:sanctum')->group(function() {
        Route::post('logout', [AuthController::class, 'logout']);
        Route::apiResource('posts', PostController::class);
    });
});

Route Best Practices

When building APIs, follow these routing conventions:

  • Use versioning in your API (v1, v2)
  • Group related routes together
  • Protect sensitive routes with middleware
  • Use resource routes where appropriate
Recommended For You:
Simple And Quickest PHP File Cache Example With Auto Expiry

Implementing Authentication With Sanctum

Laravel Sanctum provides a lightweight authentication system for SPAs and mobile applications. First, install Sanctum:

composer require laravel/sanctum

Publish the Sanctum configuration files:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Creating The Auth Controller

Generate a new controller for authentication:

php artisan make:controller API/AuthController

Here’s a basic implementation for registration, login, and logout:

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ]);
        
        $user = User::create([
            'name' => $validated['name'],
            'email' => $validated['email'],
            'password' => Hash::make($validated['password']),
        ]);
        
        return response()->json([
            'token' => $user->createToken('auth_token')->plainTextToken,
            'user' => $user
        ], 201);
    }
    
    public function login(Request $request)
    {
        $request->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.'],
            ]);
        }
        
        return response()->json([
            'token' => $user->createToken('auth_token')->plainTextToken,
            'user' => $user
        ]);
    }
    
    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();
        
        return response()->json(['message' => 'Logged out successfully']);
    }
}

Database Migrations And Models

Laravel’s migration system helps version your database schema. Let’s create a migration for a posts table:

php artisan make:migration create_posts_table

Edit the migration file:

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->onDelete('cascade');
        $table->string('title');
        $table->text('content');
        $table->string('image')->nullable();
        $table->timestamps();
    });
}

Run the migration:

php artisan migrate

Creating The Post Model

Generate a model for our posts:

php artisan make:model Post

Add fillable fields and relationships:

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
    
    protected $fillable = [
        'user_id',
        'title',
        'content',
        'image'
    ];
    
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Building The Post Controller

Create a controller for post operations:

php artisan make:controller API/PostController --api

Implement the resource methods:

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::with('user')->latest()->paginate(10);
        return response()->json($posts);
    }
    
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
            'image' => 'nullable|image|max:2048',
        ]);
        
        if ($request->hasFile('image')) {
            $validated['image'] = $request->file('image')->store('posts');
        }
        
        $validated['user_id'] = auth()->id();
        
        $post = Post::create($validated);
        
        return response()->json($post, 201);
    }
    
    public function show(Post $post)
    {
        return response()->json($post->load('user'));
    }
    
    public function update(Request $request, Post $post)
    {
        $this->authorize('update', $post);
        
        $validated = $request->validate([
            'title' => 'sometimes|string|max:255',
            'content' => 'sometimes|string',
            'image' => 'sometimes|image|max:2048',
        ]);
        
        if ($request->hasFile('image')) {
            if ($post->image) {
                Storage::delete($post->image);
            }
            $validated['image'] = $request->file('image')->store('posts');
        }
        
        $post->update($validated);
        
        return response()->json($post);
    }
    
    public function destroy(Post $post)
    {
        $this->authorize('delete', $post);
        
        if ($post->image) {
            Storage::delete($post->image);
        }
        
        $post->delete();
        
        return response()->json(null, 204);
    }
}

Handling File Uploads With FormData

When working with APIs, you’ll often need to handle file uploads. Laravel makes this straightforward:

Recommended For You:
Best PHP Framework To Start For Your Small Web Application

Configuring File Storage

Ensure your .env has proper storage configuration:

FILESYSTEM_DISK=local

Create a symbolic link to make uploaded files accessible:

php artisan storage:link

Uploading Files Via API

When sending files via API, use FormData in your frontend application. Here’s how Laravel handles it:

// In your controller
if ($request->hasFile('image')) {
    $path = $request->file('image')->store('posts');
    // Save $path to your database
}

Laravel-API-Boilerplate

API Response Formatting

Consistent response formatting is crucial for API consumers. Let’s implement a standardized response structure.

Creating A Base API Controller

php artisan make:controller API/BaseController

Add response helper methods:

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;

class BaseController extends Controller
{
    public function sendResponse($result, $message = '', $code = 200): JsonResponse
    {
        $response = [
            'success' => true,
            'data' => $result,
            'message' => $message,
        ];
        
        return response()->json($response, $code);
    }
    
    public function sendError($error, $errorMessages = [], $code = 404): JsonResponse
    {
        $response = [
            'success' => false,
            'message' => $error,
        ];
        
        if (!empty($errorMessages)) {
            $response['data'] = $errorMessages;
        }
        
        return response()->json($response, $code);
    }
}

Using The Response Helpers

Update your controllers to extend BaseController and use these methods:

// Success response
return $this->sendResponse($post, 'Post retrieved successfully');

// Error response
return $this->sendError('Post not found', [], 404);

Testing Your API

Laravel provides excellent testing capabilities. Let’s create basic API tests.

Creating Feature Tests

php artisan make:test AuthTest

Write test cases for authentication:

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AuthTest extends TestCase
{
    use RefreshDatabase;
    
    public function test_user_can_register()
    {
        $response = $this->postJson('/api/v1/register', [
            'name' => 'Test User',
            'email' => 'test@example.com',
            'password' => 'password',
            'password_confirmation' => 'password',
        ]);
        
        $response->assertStatus(201)
            ->assertJsonStructure([
                'token',
                'user' => ['id', 'name', 'email']
            ]);
    }
    
    public function test_user_can_login()
    {
        $user = User::factory()->create([
            'email' => 'test@example.com',
            'password' => bcrypt('password'),
        ]);
        
        $response = $this->postJson('/api/v1/login', [
            'email' => 'test@example.com',
            'password' => 'password',
        ]);
        
        $response->assertStatus(200)
            ->assertJsonStructure([
                'token',
                'user' => ['id', 'name', 'email']
            ]);
    }
}

API Documentation With OpenAPI/Swagger

Documenting your API is essential for developer adoption. Let’s set up Swagger documentation.

Recommended For You:
How To Export MySQL Database Tables To CSV Format Using PHP?

Installing L5-Swagger

composer require darkaonline/l5-swagger

Publish the configuration:

php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"

Adding API Annotations

Document your endpoints using PHPDoc annotations:

/**
 * @OA\Post(
 *     path="/api/v1/register",
 *     summary="Register a new user",
 *     @OA\RequestBody(
 *         @OA\MediaType(
 *             mediaType="application/json",
 *             @OA\Schema(
 *                 @OA\Property(
 *                     property="name",
 *                     type="string"
 *                 ),
 *                 @OA\Property(
 *                     property="email",
 *                     type="string"
 *                 ),
 *                 @OA\Property(
 *                     property="password",
 *                     type="string"
 *                 ),
 *                 @OA\Property(
 *                     property="password_confirmation",
 *                     type="string"
 *                 ),
 *                 example={"name": "Test User", "email": "test@example.com", "password": "password", "password_confirmation": "password"}
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=201,
 *         description="User registered successfully",
 *         @OA\JsonContent(
 *             @OA\Property(property="token", type="string"),
 *             @OA\Property(property="user", type="object")
 *         )
 *     )
 * )
 */
public function register(Request $request) { ... }

Deploying Your API

When ready to deploy your Laravel API, follow these best practices:

  • Set APP_ENV=production in your .env
  • Generate an application key: php artisan key:generate
  • Optimize performance: php artisan optimize
  • Set up proper file permissions
  • Implement HTTPS for security

Conclusion

You’ve now built a comprehensive Laravel API boilerplate with authentication, CRUD operations, file uploads, and proper response formatting. This foundation can be extended for various API projects. Remember to:

  • Implement proper validation for all endpoints
  • Add rate limiting to prevent abuse
  • Write comprehensive tests
  • Document your API thoroughly

For more advanced Laravel techniques, check out our guide on Advanced Laravel Techniques or learn about Building Microservices with Laravel.

You Like It, Please Share This Recipe With Your Friends Using...

Be the first to write a comment.

Leave a Reply

Your email address will not be published. Required fields are marked *