nomanurrahman/api-starter-kit

A complete Laravel API boilerplate with authentication, transformers, exception handling, and scaffolding commands

Maintainers

Package info

github.com/nomanur/laravel-api-starter-kit

Homepage

pkg:composer/nomanurrahman/api-starter-kit

Statistics

Installs: 17

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.0.6 2026-04-07 14:49 UTC

This package is auto-updated.

Last update: 2026-04-07 14:50:52 UTC


README

Latest Version on Packagist Total Downloads PHP Version Laravel Version License

A complete, production-ready Laravel API boilerplate with authentication, transformers, exception handling, rate limiting, and scaffolding commands. Build APIs faster with a standardized structure and best practices built-in.

๐Ÿš€ Features

  • โœ… Standardized API Responses - Consistent JSON response format
  • โœ… Fractal Transformers - Clean data transformation layer
  • โœ… Exception Handling - Centralized error handling for all API errors
  • โœ… Rate Limiting - Built-in API rate limiting middleware
  • โœ… Authentication - Laravel Sanctum integration ready
  • โœ… Scaffolding Commands - Generate API resources with one command
  • โœ… Pagination Support - Built-in pagination with metadata
  • โœ… Caching - Optional response caching
  • โœ… CORS Support - Cross-origin request handling
  • โœ… Validation - Standardized validation error responses
  • โœ… Base Controllers & Models - Extendable foundation classes

๐Ÿ“ฆ Installation

Requirements

  • PHP 8.0 or higher
  • Laravel 9.0 or higher
  • Composer

Install via Composer

composer require nomanurrahman/api-starter-kit

Quick Setup

Run the installation command to set up everything automatically:

php artisan api-starter-kit:install --sanctum --migrations

This will:

  • Publish the configuration file
  • Install Laravel Sanctum for authentication
  • Publish database migrations
  • Configure exception handling
  • Register middleware
  • Create helper functions

Manual Setup

If you prefer manual setup:

  1. Publish the configuration file:
php artisan vendor:publish --tag=api-starter-kit-config
  1. Add the service provider to config/app.php (if not auto-discovered):
'providers' => [
    // ...
    LaravelApi\StarterKit\ApiStarterKitServiceProvider::class,
],
  1. Add the facade alias to config/app.php:
'aliases' => [
    // ...
    'ApiBoilerplate' => LaravelApi\StarterKit\ApiBoilerplateFacade::class,
],
  1. Register middleware in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'api.auth' => \LaravelApi\StarterKit\Http\Middleware\ApiAuthenticate::class,
        'api.rate_limit' => \LaravelApi\StarterKit\Http\Middleware\ApiRateLimit::class,
        'api.cors' => \LaravelApi\StarterKit\Http\Middleware\ApiCors::class,
    ]);
})

๐Ÿ“– Usage

Creating Your First API Resource

The easiest way to create a complete API resource is using the artisan command:

php artisan make:api-resource Post

This will create:

  • Model: app/Models/Post.php
  • Controller: app/Http/Controllers/Api/PostsController.php
  • Transformer: app/Transformers/PostTransformer.php
  • Routes: Added to routes/api.php

You can also specify custom names:

php artisan make:api-resource Post --model=Article --controller=ArticlesController --transformer=ArticleTransformer

API Response Format

All API responses follow a standardized format:

Success Response:

{
    "data": {
        "id": 1,
        "title": "My Post",
        "content": "Post content here",
        "created_at": "2024-01-01T00:00:00+00:00"
    },
    "message": "Post retrieved successfully"
}

Error Response:

{
    "error": "Validation failed",
    "errors": {
        "title": ["The title field is required."],
        "content": ["The content field must be at least 10 characters."]
    }
}

Paginated Response:

{
    "data": [...],
    "message": "Posts retrieved successfully",
    "meta": {
        "current_page": 1,
        "last_page": 5,
        "per_page": 15,
        "total": 75,
        "from": 1,
        "to": 15
    },
    "links": {
        "self": "http://example.com/api/v1/posts?page=1",
        "first": "http://example.com/api/v1/posts?page=1",
        "last": "http://example.com/api/v1/posts?page=5",
        "next": "http://example.com/api/v1/posts?page=2",
        "prev": null
    }
}

Using the Base Controller

Extend the ApiController in your controllers to get all the helper methods:

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\ApiController;
use App\Models\User;
use App\Transformers\UserTransformer;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class UserController extends ApiController
{
    public function __construct()
    {
        parent::__construct();

        $this->middleware('transform.input:'.UserTransformer::class)->only(['store', 'update']);
    }

    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $users = User::all();
        return $this->showAll($users);
    }

    public function store(Request $request)
    {
        $rules = [
            'name' => 'required',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:6|confirmed',
        ];

        $this->validate($request, $rules);

        $data = $request->except('password_confirmation');
        $data['password'] = bcrypt($request->password);
        $data['verified'] = User::UNVERIFIED_USER;
        $data['verification_token'] = User::generateVerificationCode();
        $data['admin'] = User::REGULAR_USER;

        $user = User::create($data);

        return $this->showOne($user, 201);
    }

    public function show(User $user)
    {
        return $this->showOne($user);
    }

    public function update(Request $request, User $user)
    {
        $rules = [
            'email' => 'email|unique:users,email,'.$user->id,
            'password' => 'min:6|confirmed',
            'admin' => 'in:'.User::ADMIN_USER.','.User::REGULAR_USER,
        ];

        $this->validate($request, $rules);

        if ($request->has('name')) {
            $user->name = $request->name;
        }

        if ($request->has('email') && $user->email != $request->email) {
            $user->verified = User::UNVERIFIED_USER;
            $user->verification_token = User::generateVerificationCode();
            $user->email = $request->email;
        }

        if ($request->has('password')) {
            $user->password = bcrypt($request->password);
        }

        if ($request->has('admin')) {
            if (!$user->isVerified()) {
                return $this->errorResponse('Only verified users can modify the admin field', 409);
            }

            $user->admin = $request->admin;
        }

        if (!$user->isDirty()) {
            return $this->errorResponse('You need to specify a different value to update', 422);
        }

        $user->save();

        return $this->showOne($user);
    }

    public function destroy(User $user)
    {
        $user->delete();
        return $this->showOne($user);
    }

    public function showMessage(string $message, int $code = 200)
    {
        return $this->successResponse(['data' => $message], $code);
    }
}

Using Transformers

Transformers provide a clean way to format your API responses:

<?php

namespace App\Transformers;

use App\Models\Post;
use LaravelApi\StarterKit\Transformers\BaseTransformer;

class PostTransformer extends BaseTransformer
{
    public function transform(Post $post): array
    {
        return [
            'id' => $post->id,
            'title' => $post->title,
            'content' => $post->content,
            'author' => $post->author?->name,
            'published' => $post->published_at?->toIso8601String(),
            'created_at' => $post->created_at->toIso8601String(),
            'updated_at' => $post->updated_at->toIso8601String(),
        ];
    }

    public static function originalAttribute(string $index): ?string
    {
        $attributes = [
            'id' => 'id',
            'title' => 'title',
            'content' => 'content',
            'author' => 'author',
            'published' => 'published_at',
            'created_at' => 'created_at',
            'updated_at' => 'updated_at',
        ];

        return $attributes[$index] ?? null;
    }

    public static function transformedAttribute(string $index): ?string
    {
        $attributes = [
            'id' => 'id',
            'title' => 'title',
            'content' => 'content',
            'author' => 'author',
            'published' => 'published_at',
            'created_at' => 'created_at',
            'updated_at' => 'updated_at',
        ];

        return $attributes[$index] ?? null;
    }
}

Using the Model

Extend ApiModel for automatic transformer support:

<?php

namespace App\Models;

use LaravelApi\StarterKit\Models\ApiModel;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Post extends ApiModel
{
    use HasFactory;

    public static $transformer = \App\Transformers\PostTransformer::class;

    protected $fillable = ['title', 'content', 'published_at'];

    protected $casts = [
        'published_at' => 'datetime',
    ];
}

API Routes

Define your API routes in routes/api.php:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\PostsController;

// Public routes
Route::get('/posts', [PostsController::class, 'index']);
Route::get('/posts/{post}', [PostsController::class, 'show']);

// Protected routes
Route::middleware('api.auth')->group(function () {
    Route::post('/posts', [PostsController::class, 'store']);
    Route::put('/posts/{post}', [PostsController::class, 'update']);
    Route::delete('/posts/{post}', [PostsController::class, 'destroy']);
});

Helper Functions

The package provides helper functions for quick API responses:

// Success response
api_response($data, 'Success message', 200);

// Error response
api_error('Error message', 400, $errors);

// Paginated response
api_paginated($paginator, 'Success message', 200);

โš™๏ธ Configuration

Publish the configuration file to customize settings:

php artisan vendor:publish --tag=api-starter-kit-config

Configuration options in config/api-starter-kit.php:

  • prefix: API URL prefix (default: api)
  • version: API version (default: v1)
  • rate_limit: Rate limiting settings
  • auth: Authentication driver configuration
  • response: Response format keys
  • cache: Caching settings
  • exceptions: Exception handling settings
  • validation: Validation error format

๐Ÿ”’ Authentication

Using Sanctum (Recommended)

  1. Install Sanctum:
php artisan api-starter-kit:install --sanctum
  1. Protect routes with middleware:
Route::middleware('api.auth')->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user();
    });
});
  1. Authenticate users via tokens:
curl -H "Authorization: Bearer YOUR_TOKEN" http://example.com/api/v1/user

๐Ÿ›ก๏ธ Middleware

The package includes three middleware classes:

  • ApiAuthenticate: Handles API authentication
  • ApiRateLimit: Rate limiting for API endpoints
  • ApiCors: CORS headers for cross-origin requests

Apply them to routes:

Route::middleware(['api.auth', 'api.rate_limit'])->group(function () {
    // Protected and rate-limited routes
});

๐ŸŽฏ Query Parameters

The API supports various query parameters for filtering and pagination:

  • per_page: Items per page (default: 15, max: 100)
  • page: Page number
  • sort_by: Field to sort by
  • desc: Sort in descending order (true/false)
  • Custom filters based on transformer attributes

Example:

GET /api/v1/posts?per_page=10&page=2&sort_by=created_at&desc=true

๐Ÿ“ Exception Handling

All exceptions are automatically caught and returned as JSON:

  • ValidationException (422): Validation errors
  • ModelNotFoundException (404): Resource not found
  • AuthenticationException (401): Unauthenticated
  • AuthorizationException (403): Unauthorized
  • NotFoundHttpException (404): Route not found
  • MethodNotAllowedHttpException (405): Invalid HTTP method
  • QueryException (409/500): Database errors

๐Ÿงช Testing

Run the package tests:

composer test

๐Ÿ“š Examples

Complete CRUD API Example

Check the example files in the package to see a complete implementation.

Health Check Endpoint

The package includes a health check endpoint:

GET /health

Response:

{
    "status": "ok",
    "timestamp": "2024-01-01T00:00:00+00:00",
    "version": "v1"
}

๐Ÿ”ง Advanced Usage

Custom Response Keys

Configure response keys in config/api-starter-kit.php:

'response' => [
    'success_key' => 'data',
    'message_key' => 'message',
    'error_key' => 'error',
    'meta_key' => 'meta',
    'links_key' => 'links',
],

Enable Caching

Enable response caching in config:

'cache' => [
    'enabled' => true,
    'ttl' => 60, // minutes
],

Custom Rate Limits

Configure rate limiting:

'rate_limit' => [
    'enabled' => true,
    'max_attempts' => 60,
    'decay_minutes' => 1,
],

๐Ÿค Contributing

Please see CONTRIBUTING for details.

๐Ÿ” Security

If you discover any security related issues, please email nomanurrahman@gmail.com instead of using the issue tracker.

๐Ÿ“„ License

The MIT License (MIT). Please see License File for more information.

๐Ÿ‘ฅ Credits

๐Ÿ™ Support

If you find this package helpful, please โญ star it on GitHub!

For questions and support:

Happy API Building! ๐Ÿš€