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:
- Set
APP_ENV=productionin your.envfile - Generate an application key:
php artisan key:generate - Optimize the application:
php artisan optimize - Set up proper CORS configuration in
config/cors.php - Configure your web server (Nginx/Apache) to handle API requests
- Set up queue workers if using jobs
- Implement proper logging and monitoring
Best Practices for Laravel API Development
- Use API Resources: Transform your models for API responses
- Version your API:
/api/v1/posts - Implement Caching: Use Redis or other cache systems
- Handle Errors Gracefully: Custom error responses
- Use HTTPS: Always secure your API
- Implement Pagination: For large data sets
- Use API Tokens: For stateless authentication
- Rate Limiting: Protect against abuse
- Document Thoroughly: Swagger/OpenAPI documentation
- 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!
Projects to explore next
Source-code projects from the KritiMyantra catalogue. Check each project's details before buying.
Flask Authentication System (Free Version) - Kritim Yantra
🛠 Features✔ Google & GitHub Authentication✔ User Registration & Login✔ Profile/Dashboard Access✔ Secure & Mi...
Flask Blog CMS with Admin Dashboard — Python Source Code
A Flask-based blogging website with a built-in admin dashboard. Manage articles, images, categories, tags and featured p...
Laravel 12 + ReactJS Starter Kit: Add Multi-Language Support (Arabic, English, Spanish) with Blog CRUD
🚀 Installation & Setup Download & Extract Get the ZIP from kritimyantra.com and extract it. Includes preconfigu...
Comments
Sign in to join the discussion.