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!

LIVE MENTORSHIP ONLY 5 SPOTS

Laravel Mastery
Coaching Class Program

KritiMyantra

Transform from beginner to Laravel expert with our personalized Coaching Class starting June 23, 2025. Limited enrollment ensures focused attention.

Daily Sessions

1-hour personalized coaching

Real Projects

Build portfolio applications

Best Practices

Industry-standard techniques

Career Support

Interview prep & job guidance

Total Investment
$200
Duration
30 hours
1h/day

Enrollment Closes In

Days
Hours
Minutes
Seconds
Spots Available 5 of 10 remaining
Next cohort starts:
June 23, 2025

Join the Program

Complete your application to secure your spot

Application Submitted!

Thank you for your interest in our Laravel mentorship program. We'll contact you within 24 hours with next steps.

What happens next?

  • Confirmation email with program details
  • WhatsApp message from our team
  • Onboarding call to discuss your goals

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