controllers
Thin HTTP entry points that validate input, delegate to Actions or Services, and return a response. Controllers contain no business logic.
SKILL.mdresources/boost/skills/controllers/SKILL.md
GitHubControllers
When to Apply
- When creating or refactoring HTTP endpoints in
app/Http/Controllers/**. - When moving business logic out of controllers into Actions, Services, or Jobs.
- When ensuring API and web controllers follow consistent patterns for validation, authorization, and responses.
- When reviewing controllers for thinness, correct status codes, and proper delegation.
Preconditions
- Required: Routing and controller setup exists (
routes/web.php,routes/api.php). - Required: Validation and authorization paths are defined (Form Requests, policies, or middleware).
- Recommended: Actions/Services for business logic are implemented before wiring the endpoint.
- Recommended: API/web response conventions (JSON vs views) are documented for the project.
Process
1. Keep Controllers Thin
- Restrict controller responsibilities to:
- Validating and authorizing incoming requests.
- Delegating work to Actions, Services, or Jobs.
- Returning appropriate HTTP responses (JSON or views).
- Remove any:
- Direct database queries from controller methods.
- Complex branching or multi-step domain logic.
2. Use Form Requests and Authorization
- Use dedicated
FormRequestclasses for all validation:- Avoid
$request->validate()orValidator::make()directly in the controller.
- Avoid
- Enforce authorization at the controller level via:
$this->authorize()calls.- Form Request
authorize()methods. - Route or controller middleware (e.g.,
can:orauth).
3. Design Controller Structure and Naming
- For single-action endpoints, use invokable controllers (
__invoke):- Name them after the action:
StoreInvoiceController,ProcessWebhookController.
- Name them after the action:
- For resource controllers:
- Keep each method thin and delegate to appropriate Actions or Services.
- Only define the methods actually needed; prefer invokable controllers when only one or two actions exist.
4. Return Consistent Responses
- For API controllers:
- Return JSON responses (e.g.,
JsonResponseorResource/ResourceCollection). - Use appropriate HTTP status codes: 200, 201, 204, 403, 404, 422, etc.
- Use explicit
JsonResponsewhen status/header control matters; otherwise Laravel response casting is acceptable for simple payloads.
- Return JSON responses (e.g.,
- For web controllers:
- Return views or redirects, not JSON.
- Keep view data preparation simple and delegated where possible.
5. Keep Controllers Testable
- Thin controllers push logic and most assertions into Action/Service tests.
- Controller tests should focus on HTTP contract: validation, authorization, status code, and response shape.
Examples
// Invokable single-action controller
class StoreInvoiceController extends Controller
{
public function __invoke(StoreInvoiceRequest $request, CreateInvoice $action): JsonResponse
{
$invoice = $action->execute(
orderId: (int) $request->validated('order_id'),
);
return new JsonResponse(new InvoiceResource($invoice), 201);
}
}
// Resource controller — thin, delegates to actions
class InvoiceController extends Controller
{
public function index(): JsonResponse
{
// Explicit JsonResponse keeps status/header behavior clear for API controllers.
return new JsonResponse(InvoiceResource::collection(Invoice::paginate()), 200);
}
public function store(StoreInvoiceRequest $request, CreateInvoice $action): JsonResponse
{
$this->authorize('create', Invoice::class);
$invoice = $action->execute(orderId: (int) $request->validated('order_id'));
return new JsonResponse(new InvoiceResource($invoice), 201);
}
public function destroy(Invoice $invoice, DeleteInvoice $action): JsonResponse
{
$this->authorize('delete', $invoice);
$action->execute($invoice);
return new JsonResponse(null, 204);
}
}
Checklists
Execution Checklist
- Controller methods contain no business logic or direct database queries.
- All validation is handled by FormRequest classes, not inline in the controller.
- Authorization is enforced via policies, Form Requests, or middleware.
- Controllers delegate to Actions, Services, or Jobs for business operations.
- Invokable controllers are used for single-action endpoints where appropriate.
- Responses use correct types and HTTP status codes (JSON for API, views for web).
Safety / Things to Avoid
- Calling
$request->validate()directly in a controller (use a FormRequest). - Writing database queries or heavy business logic directly in controller methods.
- Using resource controllers with seven methods when only one or two are needed (prefer invokable controllers).
- Ignoring HTTP status codes or returning incorrect codes for errors and success.
- Performing authorization inside Actions instead of at the controller level.
References
- Laravel Controllers
- Related (read first):
Actions/SKILL.md— the delegation pattern used by thin controllers - Related:
FormRequests/SKILL.md— all input validation - Related:
Policies/SKILL.md— authorization enforced in controllers