Laravel
Quick Start
// routes/api.php
Route::get('/health', fn () => ['status' => 'ok']);
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('users', UserController::class);
});
Features
| Feature |
Description |
Guide |
| Models |
Eloquent ORM, relationships, scopes |
MODELS.md |
| Controllers |
Resource controllers, form requests |
CONTROLLERS.md |
| API Resources |
Response transformation |
RESOURCES.md |
| Auth |
Sanctum, policies, gates |
AUTH.md |
| Queues |
Jobs, events, listeners |
QUEUES.md |
| Testing |
Feature, unit tests |
TESTING.md |
Common Patterns
Model with Relationships
class User extends Authenticatable
{
use HasApiTokens, HasFactory, SoftDeletes;
protected $fillable = ['name', 'email', 'password', 'role'];
protected $hidden = ['password', 'remember_token'];
protected $casts = ['email_verified_at' => 'datetime', 'password' => 'hashed'];
public function organizations(): BelongsToMany
{
return $this->belongsToMany(Organization::class, 'memberships')
->withPivot('role')
->withTimestamps();
}
public function scopeActive($query)
{
return $query->where('is_active', true);
}
public function scopeSearch($query, ?string $search)
{
return $search
? $query->where('name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%")
: $query;
}
}
Controller with Service
class UserController extends Controller
{
public function __construct(private UserService $userService) {}
public function index(Request $request): PaginatedCollection
{
$users = $this->userService->list(
search: $request->input('search'),
perPage: $request->input('per_page', 20)
);
return new PaginatedCollection($users, UserResource::class);
}
public function store(CreateUserRequest $request): JsonResponse
{
$user = $this->userService->create($request->validated());
return (new UserResource($user))
->response()
->setStatusCode(201);
}
public function show(User $user): UserResource
{
return new UserResource($user->load('organizations'));
}
}
Form Request Validation
class CreateUserRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->isAdmin();
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'min:2', 'max:100'],
'email' => ['required', 'email', 'unique:users,email'],
'password' => ['required', 'confirmed', Password::min(8)->mixedCase()->numbers()],
'role' => ['sometimes', 'in:admin,user,guest'],
];
}
}
Workflows
API Development
- Create model and migration
- Create controller with
php artisan make:controller --api
- Add Form Request for validation
- Create API Resource for responses
- Write feature tests
Resource Response
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'organizations' => OrganizationResource::collection($this->whenLoaded('organizations')),
'created_at' => $this->created_at->toIso8601String(),
];
}
}
Best Practices
| Do |
Avoid |
| Use Form Requests for validation |
Validating in controllers |
| Use API Resources for responses |
Returning models directly |
| Use service classes for logic |
Fat controllers |
| Use eager loading |
N+1 queries |
| Use soft deletes |
Hard deletes for important data |
Project Structure
app/
├── Http/
│ ├── Controllers/Api/
│ ├── Requests/
│ ├── Resources/
│ └── Middleware/
├── Models/
├── Services/
├── Policies/
├── Jobs/
└── Events/
routes/
├── api.php
└── web.php
tests/
├── Feature/
└── Unit/
For detailed examples and patterns, see reference files above.