Building APIs with Laravel 12: A Comprehensive Guide

Author

Kritim Yantra

Mar 24, 2025

Building APIs with Laravel 12: A Comprehensive Guide

Laravel remains one of the most popular PHP frameworks for building robust APIs, and with Laravel 12, the process has become even more streamlined. In this guide, we'll walk through the essential steps to build a modern API with Laravel 12, covering everything from setup to deployment.

Why Choose Laravel for API Development?

Before we dive in, let's understand why Laravel is an excellent choice for API development:

  • Built-in API support with resource controllers and API routes
  • Eloquent ORM for easy database interactions
  • Robust authentication with Sanctum and Passport
  • Automatic request validation
  • Powerful error handling
  • Built-in testing tools

Step 1: Setting Up Your Laravel API Project

First, create a new Laravel project:

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

Install API:

php artisan install:api

Step 2: Configuring API Routes

Laravel separates web and API routes. All API routes go in routes/api.php:

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

Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);

Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('posts', PostController::class);
    Route::post('/logout', [AuthController::class, 'logout']);
});

Notice how we're using auth:sanctum middleware to protect our routes.

Step 3: Creating Models and Migrations

Let's create a Post model with migration:

php artisan make:model Post -m

Edit the migration file:

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

Run the migration:

php artisan migrate

Step 4: Building the Authentication System

Create an AuthController:

php artisan make:controller AuthController

Implement the authentication methods:

namespace App\Http\Controllers;

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)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8',
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        return response()->json([
            'token' => $user->createToken('api-token')->plainTextToken,
        ], 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('api-token')->plainTextToken,
        ]);
    }

    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();

        return response()->json(['message' => 'Logged out']);
    }
}

Step 5: Creating the Post Controller

Generate a controller for our posts:

php artisan make:controller PostController --api

Implement the CRUD operations:

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()
    {
        return Post::where('user_id', auth()->id())->get();
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
        ]);

        $post = Post::create([
            'user_id' => auth()->id(),
            'title' => $validated['title'],
            'content' => $validated['content'],
        ]);

        return response()->json($post, 201);
    }

    public function show(Post $post)
    {
        $this->authorize('view', $post);
        return $post;
    }

    public function update(Request $request, Post $post)
    {
        $this->authorize('update', $post);

        $validated = $request->validate([
            'title' => 'sometimes|string|max:255',
            'content' => 'sometimes|string',
        ]);

        $post->update($validated);

        return $post;
    }

    public function destroy(Post $post)
    {
        $this->authorize('delete', $post);
        $post->delete();
        return response()->noContent();
    }
}

Step 6: Implementing Policies for Authorization

Create a policy for the Post model:

php artisan make:policy PostPolicy --model=Post

Define the authorization rules in app/Policies/PostPolicy.php:

public function view(User $user, Post $post)
{
    return $user->id === $post->user_id;
}

public function update(User $user, Post $post)
{
    return $user->id === $post->user_id;
}

public function delete(User $user, Post $post)
{
    return $user->id === $post->user_id;
}

No need to register the policy manually in AuthServiceProvider.php!

In Laravel 12, if you follow the convention—placing your policies in the app/Policies directory and naming them appropriately (for example, PostPolicy for the Post model)—Laravel will automatically discover and use them.

If you don’t follow this convention (for example, if you place policies in a different folder or name them differently), you would need to register them manually using the Gate::policy() method in AppServiceProvider.

Step 7: API Response Formatting

For consistent API responses, create a trait in app/Traits/ApiResponse.php:

namespace App\Traits;

trait ApiResponse
{
    protected function success($data = null, $message = null, $code = 200)
    {
        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => $data,
        ], $code);
    }

    protected function error($message = null, $code = 400, $errors = null)
    {
        return response()->json([
            'success' => false,
            'message' => $message,
            'errors' => $errors,
        ], $code);
    }
}

Now you can use this trait in your controllers for consistent responses.

Step 8: Rate Limiting

Laravel provides built-in rate limiting. Configure it in app/Http/Kernel.php:

protected $middlewareGroups = [
    'api' => [
        'throttle:api',
        // ...
    ],
];

Then configure the rates in routes/api.php:

Route::middleware(['auth:sanctum', 'throttle:60,1'])->group(function () {
    // Your protected routes here
});

Step 9: API Documentation with OpenAPI/Swagger

For API documentation, install L5-Swagger:

composer require darkaonline/l5-swagger
php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"

Add annotations to your controllers:

/**
 * @OA\Post(
 *     path="/api/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"
 *                 ),
 *                 example={"name": "John Doe", "email": "john@example.com", "password": "secret"}
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=201,
 *         description="User registered successfully"
 *     ),
 *     @OA\Response(
 *         response=422,
 *         description="Validation error"
 *     )
 * )
 */

Generate the documentation:

php artisan l5-swagger:generate

Step 10: Testing Your API

Laravel provides excellent testing tools. Create a test:

php artisan make:test PostApiTest

Write some tests:

public function test_user_can_create_post()
{
    $user = User::factory()->create();
    $token = $user->createToken('test-token')->plainTextToken;

    $response = $this->withHeaders([
        'Authorization' => 'Bearer ' . $token,
    ])->postJson('/api/posts', [
        'title' => 'Test Post',
        'content' => 'This is a test post content',
    ]);

    $response->assertStatus(201)
        ->assertJson([
            'title' => 'Test Post',
            'content' => 'This is a test post content',
        ]);
}

Run the tests:

php artisan test

Step 11: Deployment Considerations

When deploying your Laravel API:

  1. Set APP_ENV=production in your .env file
  2. Generate an application key: php artisan key:generate
  3. Optimize the application: php artisan optimize
  4. Set up proper CORS configuration in config/cors.php
  5. Configure your web server (Nginx/Apache) to handle API requests
  6. Set up queue workers if using jobs
  7. Implement proper logging and monitoring

Best Practices for Laravel API Development

  1. Use API Resources: Transform your models for API responses
  2. Version your API: /api/v1/posts
  3. Implement Caching: Use Redis or other cache systems
  4. Handle Errors Gracefully: Custom error responses
  5. Use HTTPS: Always secure your API
  6. Implement Pagination: For large data sets
  7. Use API Tokens: For stateless authentication
  8. Rate Limiting: Protect against abuse
  9. Document Thoroughly: Swagger/OpenAPI documentation
  10. Monitor Performance: Use tools like Laravel Telescope

Conclusion

Building APIs with Laravel 12 is a straightforward process thanks to the framework's built-in features and excellent ecosystem. By following this guide, you've learned how to:

  • Set up a new Laravel API project
  • Implement authentication with Sanctum
  • Create CRUD operations with proper authorization
  • Format consistent API responses
  • Document your API
  • Test your endpoints
  • Prepare for deployment

Remember that API development is an iterative process. As your application grows, you'll need to consider additional aspects like:

  • API versioning strategies
  • More advanced authentication methods (OAuth2)
  • WebSocket integration for real-time features
  • Microservices architecture
  • API gateway implementation

Laravel provides all the tools you need to build professional-grade APIs that can scale with your application's needs. Happy coding!

Ajay Yadav

Ajay Yadav

Senior Full-Stack Engineer

7 + Years Experience

Transforming Ideas Into Digital Solutions

I architect and build high-performance web applications with modern tech:

Laravel PHP 8+ Vue.js React.js Flask Python MySQL

Response time: under 24 hours • 100% confidential

Tags

Comments

z0e

z0e

May 28, 2025 01:32 PM

Great article. However, app/Providers/AuthServiceProvider.php file is not included by default in a fresh installation. Should regstering policies be in the boot method of your AppServiceProvider instead?
K

Kritim Yantra

May 30, 2025 09:17 AM

Thanks for the heads-up! You’re right — in Laravel 12, you don’t need to manually register policies in AuthServiceProvider if you follow the naming conventions. I’ve updated the article to make this clear. Thanks again for the feedback! 🚀

Please log in to post a comment:

Sign in with Google

Related Posts