Installation Add the bundle via Composer:
composer require c4/api-bundle
Register the bundle in config/app.php under providers:
C4\ApiBundle\ApiBundle::class,
Configuration Publish the default config:
php artisan vendor:publish --provider="C4\ApiBundle\ApiServiceProvider" --tag="config"
Key config file: config/api.php (adjust api_prefix, version, and middleware).
First Use Case: Basic API Route Define a controller and route it under the API prefix:
// routes/api.php
Route::get('/users', [UserController::class, 'index']);
Test with:
php artisan route:list | grep api
Resourceful API Structure
Use C4\ApiBundle\Resource\ResourceController for RESTful endpoints:
use C4\ApiBundle\Resource\ResourceController;
class UserController extends ResourceController
{
protected $model = User::class;
protected $serializer = UserSerializer::class;
}
index, show, store, update, destroy methods.getRules(), getSerializer(), or getModel().Request/Response Handling Leverage built-in request validation and response formatting:
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string',
'email' => 'required|email',
]);
return $this->respondWithCreated($validated);
}
API Versioning Use route groups for versioning:
Route::prefix('v1')->group(function () {
Route::apiResource('users', UserController::class);
});
api.version in config/api.php.Middleware Integration Attach middleware globally or per route:
// config/api.php
'middleware' => ['api', 'auth:api'],
// Or per route
Route::middleware(['api', 'throttle:60'])->group(...);
Serialization
Define serializers for models (e.g., UserSerializer):
use C4\ApiBundle\Serializer\Serializer;
class UserSerializer extends Serializer
{
public function serialize(User $user)
{
return [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
];
}
}
Route Prefix Conflicts
api_prefix in config/api.php doesn’t clash with existing routes.php artisan route:list.Middleware Overrides
api middleware isn’t applied, verify:
config/app.php.app/Http/Kernel.php.Serializer Caching
protected static $serializerCache = [];
public function getSerializer()
{
return self::$serializerCache[$this->serializer] ??= new $this->serializer();
}
Validation Rules
use Illuminate\Validation\Rule;
$validated = $request->validate([
'email' => ['required', Rule::unique('users')->ignore($user->id)],
]);
Pagination
respondWithCollection() for paginated responses:
return $this->respondWithCollection(User::paginate(10));
config/api.php (paginate.per_page).Log API Requests: Add a middleware to log requests:
// app/Http/Middleware/LogApiRequests.php
public function handle($request, Closure $next)
{
\Log::info('API Request', $request->all());
return $next($request);
}
Register it in app/Http/Kernel.php.
Check Headers: Ensure Accept: application/json is set for JSON responses.
Custom Responses
Extend C4\ApiBundle\Response\ApiResponse for custom formats:
class CustomApiResponse extends ApiResponse
{
public function success($data, $message = null)
{
return response()->json([
'success' => true,
'data' => $data,
'message' => $message,
'custom_field' => 'value',
]);
}
}
Event Listeners
Listen to API events (e.g., api.request, api.response):
// EventServiceProvider
protected $listen = [
'api.request' => [LogApiRequest::class],
];
Testing
Use C4\ApiBundle\Testing\TestCase for API tests:
use C4\ApiBundle\Testing\TestCase;
class UserTest extends TestCase
{
public function testGetUsers()
{
$response = $this->getJson('/api/v1/users');
$response->assertStatus(200);
}
}
How can I help you explore Laravel packages today?