The Non-negotiable API Standards
Every Laravel API we build follows these rules from day one. No exceptions.
1. Version from the Start
// routes/api.php
Route::prefix('v1')->group(base_path('routes/api_v1.php'));
Route::prefix('v2')->group(base_path('routes/api_v2.php'));Even if you never need v2, versioning signals to API consumers that you take backwards compatibility seriously.
2. Consistent Response Structure
Every response — success or error — follows the same envelope:
{
"success": true,
"data": { },
"message": "Resource created successfully",
"meta": { "pagination": {} }
}Use an ApiResponse trait to enforce this across all controllers.
3. Sanctum for SPA Auth, Passport for Third-party OAuth
Don't mix them up. Sanctum's cookie-based auth is perfect for first-party SPAs and mobile apps. Passport is for when you're building an OAuth provider for third parties.
4. Rate Limiting by User Tier
RateLimiter::for('api', function (Request $request) {
return $request->user()->isPro()
? Limit::perMinute(300)
: Limit::perMinute(60);
});5. Form Request Classes for Every Mutation
Never validate in controllers. Every POST/PUT/PATCH gets a dedicated FormRequest class with authorization and validation rules. This keeps controllers thin and makes validation testable in isolation.
6. API Resources for Every Response
Never return Eloquent models directly. Always transform through API Resources. This gives you a stable contract even when your database schema changes.
Testing: Feature Tests Over Unit Tests for APIs
For APIs, feature tests that hit actual routes and assert response structure catch far more real bugs than unit tests on individual methods. We target 80% feature test coverage on API endpoints.
