DEV Community

Mike Birhanu
Mike Birhanu

Posted on

Build Your Own Laravel API Boilerplate (with Sanctum, Traits & Automation)

A step-by-step guide to creating a scalable, maintainable Laravel API starter—using real code, real repos, and real-world patterns.


Why This Guide?

  • Consistent API responses (no more frontend confusion)
  • Reusable traits (DRY, testable code)
  • Extendable base controllers (easy to scale)
  • Built-in authentication (Sanctum)
  • Automated scaffolding (Artisan commands)
  • Repo links for every step

1️⃣ Project Setup: Start Clean

a) Create a new Laravel project:

composer create-project laravel/laravel my-api
cd my-api
Enter fullscreen mode Exit fullscreen mode

Laravel Installation Docs

b) Add Sanctum for API auth:

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Sanctum Docs

c) Set up your API routes:

Edit routes/api.php and use the auth:sanctum middleware for protected endpoints:

Route::middleware('auth:sanctum')->get('/user', fn(Request $request) => $request->user());
Enter fullscreen mode Exit fullscreen mode

2️⃣ Traits: The Secret to DRY, Consistent APIs

a) HandlesApiResponse

Standardize every response—success or error.

View on GitHub

// app/Concerns/HandlesApiResponse.php
trait HandlesApiResponse
{
    public function respondSuccess($data = null, string $message = '', int $status = 200)
    {
        return response()->json([
            'success' => true,
            'data' => $data,
            'message' => $message,
            'errors' => null
        ], $status);
    }

    public function respondError(string $message, int $code = 422, $errors = null)
    {
        return response()->json([
            'success' => false,
            'data' => null,
            'message' => $message,
            'errors' => $errors
        ], $code);
    }
}
Enter fullscreen mode Exit fullscreen mode

b) HandlesValidation

Centralize validation logic.

View on GitHub

// app/Concerns/HandlesValidation.php
trait HandlesValidation
{
    public function validateRequest(Request $request, array $rules)
    {
        return $request->validate($rules);
    }
}
Enter fullscreen mode Exit fullscreen mode

Usage Example:

class UserController extends BaseApiController
{
    public function store(Request $request)
    {
        $data = $this->validateRequest($request, [
            'email' => 'required|email|unique:users'
        ]);
        return $this->respondSuccess(User::create($data), 'User created', 201);
    }
}
Enter fullscreen mode Exit fullscreen mode

3️⃣ Base Controllers: Your API's Foundation

a) BaseApiController

Centralize traits and error handling.

View on GitHub

class BaseApiController extends Controller
{
    use HandlesApiResponse, HandlesValidation;

    public function handleRequest(callable $action, string $successMessage)
    {
        try {
            $result = $action();
            return $this->respondSuccess($result, $successMessage);
        } catch (Throwable $e) {
            return $this->respondError($e->getMessage());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

b) ProtectedApiController

Auto-protect endpoints with Sanctum.

View on GitHub

class ProtectedApiController extends BaseApiController
{
    public function __construct()
    {
        $this->middleware('auth:sanctum');
    }
}
Enter fullscreen mode Exit fullscreen mode

Usage Example:

ProfileController Example

class ProfileController extends ProtectedApiController
{
    public function index()
    {
        return $this->respondSuccess(auth()->user(), 'Profile loaded');
    }
}
Enter fullscreen mode Exit fullscreen mode

4️⃣ Automate with Artisan: No More Boilerplate

Create a custom command to scaffold controllers, requests, and resources:

php artisan make:api-resource Post
Enter fullscreen mode Exit fullscreen mode

See Implementation

This generates:

  • PostController
  • PostResource
  • StorePostRequest / UpdatePostRequest
  • PostPolicy

5️⃣ Response Standards: Make Frontend Happy

Success:

{
    "success": true,
    "data": { "id": 1, "name": "John" },
    "message": "User loaded",
    "errors": null
}
Enter fullscreen mode Exit fullscreen mode

Error:

{
    "success": false,
    "data": null,
    "message": "Validation failed",
    "errors": { "email": ["Invalid email"] }
}
Enter fullscreen mode Exit fullscreen mode

6️⃣ Your Next Steps

  1. Clone the boilerplate or this variant.
  2. Run php artisan serve.
  3. Build your first endpoint in minutes.
  4. Try the challenge: Add a DELETE /posts/{id} endpoint with ownership checks (solution here).

Why This Works

  • No more spaghetti code: Traits and base controllers keep things DRY and testable.
  • Frontend-friendly: Predictable, consistent responses.
  • Easy to extend: Add features without rewriting core logic.
  • Battle-tested: Used in real projects (see repo stars & issues).

References & Further Reading


Ready to build? Fork, clone, and make it yours!

Questions? Open an issue on the repo or reach out to the community.

Top comments (0)