Building a RESTful API with Laravel: A Complete Guide

Building a RESTful API with Laravel: A Complete Guide

A deep dive into building production-ready RESTful APIs with Laravel — covering project setup, resource controllers, API resources, authentication with Sanctum, rate limiting, versioning, testing, and deployment best practices.

Whether you're building a mobile backend, a microservice, or a headless CMS, APIs are the backbone of modern software. Laravel provides one of the most elegant frameworks for building them. In this guide, I'll walk you through every step of building a production-ready RESTful API — from project scaffolding to authentication, versioning, testing, and deployment.

This isn't a surface-level overview. We'll cover the patterns and practices I use in real-world projects that serve thousands of requests per minute.


Why Laravel for APIs?

Laravel stands out for API development because of its first-class support for:

  • Eloquent ORM with eager loading and query scopes for efficient data access
  • API Resources for consistent, transformable JSON responses
  • Form Requests for clean, reusable validation logic
  • Sanctum for lightweight token-based authentication
  • Built-in rate limiting to protect your endpoints
  • Comprehensive testing tools with PHPUnit and Pest

Other frameworks can do these things, but Laravel bundles them into a cohesive, well-documented ecosystem.


Setting Up the Project

Start by creating a fresh Laravel project. I recommend the latest stable release:

composer create-project laravel/laravel api-project
cd api-project

Next, configure your .env file for your database:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=api_project
DB_USERNAME=root
DB_PASSWORD=
php artisan migrate

Designing Your Database Schema

Good API design starts with a solid data model. Let's build a blog API with posts, categories, and tags:

php artisan make:model Post -mf
php artisan make:model Category -mf
php artisan make:model Tag -mf
Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->foreignId('category_id')->nullable()->constrained()->nullOnDelete();
    $table->string('title');
    $table->string('slug')->unique();
    $table->text('excerpt')->nullable();
    $table->longText('content');
    $table->enum('status', ['draft', 'published', 'archived'])->default('draft');
    $table->timestamp('published_at')->nullable();
    $table->timestamps();
});

Building Resource Controllers

Laravel's resource controllers map RESTful actions to controller methods automatically:

php artisan make:controller Api/PostController --api --model=Post
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\PostResource;
use App\Models\Post;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::with(['user', 'category', 'tags'])
            ->published()
            ->latest()
            ->paginate(15);

        return PostResource::collection($posts);
    }

    public function store(StorePostRequest $request): PostResource
    {
        $post = Post::create($request->validated());
        return new PostResource($post->load(['user', 'category', 'tags']));
    }

    public function show(Post $post): PostResource
    {
        return new PostResource($post->load(['user', 'category', 'tags']));
    }

    public function destroy(Post $post)
    {
        $post->delete();
        return response()->json(null, 204);
    }
}

Authentication with Sanctum

Laravel Sanctum provides lightweight authentication for SPAs and token-based APIs:

php artisan install:api
// routes/api.php
Route::post('/login', [AuthController::class, 'login']);

// Public routes
Route::get('/posts', [PostController::class, 'index']);
Route::get('/posts/{post}', [PostController::class, 'show']);

// Protected routes
Route::middleware('auth:sanctum')->group(function () {
    Route::post('/posts', [PostController::class, 'store']);
    Route::put('/posts/{post}', [PostController::class, 'update']);
    Route::delete('/posts/{post}', [PostController::class, 'destroy']);
});

Always use HTTPS in production when using token-based authentication. Tokens sent over HTTP can be intercepted.


Rate Limiting

// app/Providers/AppServiceProvider.php
RateLimiter::for('api', function (Request $request) {
    return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});

Testing Your API

it('lists published posts', function () {
    Post::factory()->published()->count(5)->create();

    $response = $this->getJson('/api/posts');

    $response->assertOk()
        ->assertJsonCount(5, 'data');
});

it('requires authentication to create a post', function () {
    $this->postJson('/api/posts', ['title' => 'Test'])
        ->assertUnauthorized();
});

Conclusion

Building a RESTful API with Laravel is a rewarding experience. The framework provides everything you need out of the box.

Key takeaways:

  • Use API Resources to control your response format
  • Use Form Requests to keep validation clean and reusable
  • Use Sanctum for simple, secure token-based auth
  • Rate limit your endpoints to prevent abuse
  • Write tests — they catch bugs before your users do

Start with these patterns, and you'll have a solid foundation for any API project.

Share This Article

Comments

Get In Touch

I'm always open to discussing new projects and opportunities.

Location Yassa/Douala, Cameroon
Availability Open for opportunities

Connect With Me

Send a Message

Have a project in mind? Let's talk about it.