Laravel ‐ Chapter 13 - pierre-akhrass/Lavarel-Docs GitHub Wiki

Chapter 13: REST APIs in Laravel

This chapter guides you through building a RESTful API using Laravel 11+, including authentication, routing, controller setup, request validation, response formatting, exception handling, and API testing.


1. What is a REST API?

A REST (Representational State Transfer) API is an interface between systems that uses HTTP methods (GET, POST, PUT, DELETE) to access and modify resources, often returned in JSON format.


2. Setting Up api.php in Laravel 11

Laravel 11 no longer publishes the api.php route file by default.

To enable it:

php artisan install:api

This:

  • Publishes routes/api.php
  • Installs Laravel Sanctum for authentication

The API endpoints will now be available at URLs like:

http://yourdomain.test/api/post

3. Defining API Routes

In routes/api.php:

use App\Http\Controllers\Api\CategoryController;
use App\Http\Controllers\Api\PostController;

Route::resource('category', CategoryController::class)->except(['create', 'edit']);
Route::resource('post', PostController::class)->except(['create', 'edit']);

except(['create', 'edit']) Since you're building an API, you don’t need the routes that return HTML forms (create and edit), because APIs usually send/receive JSON, not HTML forms.


4. Creating API Controllers

Generate controllers:

php artisan make:controller Api/PostController -m Post
php artisan make:controller Api/CategoryController -m Category

Each controller uses:

  • Form Requests (StoreRequest, PutRequest) for validation
  • JSON responses using response()->json()

Example: CategoryController

The below code fetches ten categories per page.

public function index(): JsonResponse {
    return response()->json(Category::paginate(10));
}

5. Custom JSON Output

To include relationships: the below code tells Laravel to load the related Category model for each post.

public function index() {
    return response()->json(Post::with('category')->paginate(10));
}

6. Exception Handling

In bootstrap/app.php:

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (NotFoundHttpException $e, $request) {
        if ($request->expectsJson()) {
            return response()->json('Not found', 404);
        }
    });
})

7. Testing the API (Postman)

Use Postman to test API routes.

Method Endpoint
GET /api/post
GET /api/post/{id}
POST /api/post
PUT /api/post/{id}
DELETE /api/post/{id}

Use Accept: application/json header.


8. Custom Methods

All Records:

public function all(): JsonResponse {
    return response()->json(Post::get());
}

By Slug:

public function slug($slug): JsonResponse {
    return response()->json(Post::with('category')->where('slug', $slug)->firstOrFail());
}

Route:

Route::get('post/slug/{slug}', [PostController::class, 'slug']);

Or with route binding:

Route::get('post/slug/{post:slug}', [PostController::class, 'slug']);

9. Authentication with Sanctum

Sanctum provides token-based authentication.

Setup:

Already installed with:

php artisan install:api

Enable in User.php: hasApiTokens is added to the User model to enable token creation and validation.

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable {
    use HasApiTokens, ...;
}

Login Controller:

public function login(Request $request) {
    $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);

    if (auth()->attempt($request->only('email', 'password'))) {
        $token = auth()->user()->createToken('api-token')->plainTextToken;
        return response()->json($token);
    }

    return response()->json('Invalid credentials', 422);
}

Add route:

Route::post('user/login', [UserController::class, 'login']);

Use header: When the client (e.g., frontend app, mobile app) calls API routes that require authentication, it must: Include the token in the HTTP Authorization header like this: (used to access protected resources)

Authorization: Bearer YOUR_TOKEN_HERE

10. Protecting Routes

Use Sanctum middleware: This middleware:

Checks if the incoming API request includes a valid Sanctum token in the Authorization: Bearer TOKEN header. If valid, the request proceeds and the user is authenticated. If not valid or missing, Laravel returns a 401 Unauthorized response.

Route::middleware('auth:sanctum')->group(function () {
    Route::resource('category', CategoryController::class)->except(['create', 'edit']);
    Route::resource('post', PostController::class)->except(['create', 'edit']);
});

11. Using Axios or Vue for Authentication

When using Laravel Sanctum to protect your API routes, especially when your frontend and backend are served from the same domain (or trusted subdomains), Laravel expects CSRF protection on state-changing requests (like POST, PUT, DELETE).

Even though Sanctum uses token-based auth, CSRF tokens are still required to protect against cross-site request forgery in some setups (like SPA on the same domain).

In resources/js/bootstrap.js:

axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;

Example:

axios.get('/sanctum/csrf-cookie').then(() => {
    axios.post('/api/user/login', {
        email: '[email protected]',
        password: '12345'
    }).then(res => console.log(res.data));
});