Learn how to build RESTful APIs with Laravel
Transform model data for API responses
// app/Http/Resources/PostResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'slug' => $this->slug,
'author' => new UserResource($this->whenLoaded('user')),
'created_at' => $this->created_at->format('Y-m-d H:i:s'),
'updated_at' => $this->updated_at->format('Y-m-d H:i:s'),
];
}
}
// Controller
public function index()
{
$posts = Post::with('user')->paginate(10);
return PostResource::collection($posts);
}
public function show(Post $post)
{
return new PostResource($post->load('user'));
}
RESTful API endpoints implementation
// app/Http/Controllers/Api/PostController.php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\PostResource;
use App\Http\Requests\PostRequest;
use App\Models\Post;
class PostController extends Controller
{
public function index()
{
$posts = Post::with('user')
->latest()
->paginate(10);
return PostResource::collection($posts);
}
public function store(PostRequest $request)
{
$post = $request->user()
->posts()
->create($request->validated());
return new PostResource($post);
}
public function show(Post $post)
{
return new PostResource(
$post->load('user', 'comments')
);
}
public function update(PostRequest $request, Post $post)
{
$this->authorize('update', $post);
$post->update($request->validated());
return new PostResource($post);
}
public function destroy(Post $post)
{
$this->authorize('delete', $post);
$post->delete();
return response()->json([
'message' => 'Post deleted successfully'
]);
}
}
Secure API endpoints with Laravel Sanctum
// routes/api.php
Route::post('/login', [AuthController::class, 'login']);
Route::post('/register', [AuthController::class, 'register']);
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('posts', PostController::class);
Route::post('/logout', [AuthController::class, 'logout']);
});
// app/Http/Controllers/Api/AuthController.php
public function login(Request $request)
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
if (!Auth::attempt($credentials)) {
return response()->json([
'message' => 'Invalid credentials'
], 401);
}
$user = $request->user();
$token = $user->createToken('auth-token')->plainTextToken;
return response()->json([
'token' => $token,
'user' => new UserResource($user)
]);
}
// Example with Axios
const api = axios.create({
baseURL: 'http://api.example.com',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
// Login
const response = await api.post('/login', {
email: 'user@example.com',
password: 'password'
});
// Set token for subsequent requests
api.defaults.headers.common['Authorization'] =
`Bearer ${response.data.token}`;
// Make authenticated request
const posts = await api.get('/posts');
Document your API with OpenAPI/Swagger
openapi: 3.0.0
info:
title: Blog API
version: 1.0.0
description: API for managing blog posts
paths:
/api/posts:
get:
summary: List all posts
tags: [Posts]
security:
- bearerAuth: []
parameters:
- in: query
name: page
schema:
type: integer
responses:
200:
description: List of posts
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Post'
post:
summary: Create a new post
tags: [Posts]
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PostRequest'
responses:
201:
description: Post created successfully
Write tests for your API endpoints
// tests/Feature/Api/PostTest.php
namespace Tests\Feature\Api;
use Tests\TestCase;
use App\Models\User;
use App\Models\Post;
use Laravel\Sanctum\Sanctum;
class PostTest extends TestCase
{
public function test_can_list_posts()
{
$user = User::factory()->create();
$posts = Post::factory()->count(3)->create();
Sanctum::actingAs($user);
$response = $this->getJson('/api/posts');
$response->assertOk()
->assertJsonCount(3, 'data')
->assertJsonStructure([
'data' => [
'*' => ['id', 'title', 'content']
]
]);
}
public function test_can_create_post()
{
$user = User::factory()->create();
Sanctum::actingAs($user);
$response = $this->postJson('/api/posts', [
'title' => 'Test Post',
'content' => 'Test Content'
]);
$response->assertCreated()
->assertJsonPath('data.title', 'Test Post');
$this->assertDatabaseHas('posts', [
'title' => 'Test Post',
'user_id' => $user->id
]);
}
}
Essential packages for API development
# Authentication
composer require laravel/sanctum
# API Documentation
composer require "darkaonline/l5-swagger"
# API Rate Limiting
composer require spatie/laravel-rate-limiting
# API Versioning
composer require "dingo/api"