Service Layer Pattern: Keeping Controllers Thin
Move business logic into services so controllers focus only on HTTP concerns.
Amanda Reed
October 2, 2025
8.4k397
As applications grow, controllers can become bloated. A service layer keeps code organized by separating responsibilities.
Controller should focus on:
- reading request
- validation
- returning response
Service should focus on:
- business rules
- multi-step database updates
- external API calls
## Example: OrderService
```php
class OrderService {
public function createOrder(User $user, array $items): Order {
return DB::transaction(function () use ($user, $items) {
$order = Order::create([
'user_id' => $user->id,
'status' => 'pending',
'total' => 0,
]);
$total = 0;
foreach ($items as $it) {
$order->items()->create([
'product_id' => $it['product_id'],
'qty' => $it['qty'],
'price' => $it['price'],
]);
$total += $it['qty'] * $it['price'];
}
$order->update(['total' => $total]);
return $order;
});
}
}
```
Controller:
```php
public function store(Request $request, OrderService $service) {
$data = $request->validate([
'items' => 'required|array|min:1',
'items.*.product_id' => 'required|integer',
'items.*.qty' => 'required|integer|min:1',
'items.*.price' => 'required|numeric|min:0',
]);
$order = $service->createOrder($request->user(), $data['items']);
return response()->json($order, 201);
}
```
## Graph: responsibility separation
```mermaid
flowchart LR
A[Controller] --> B[Service Layer]
B --> C[Models/DB]
B --> D[External APIs]
```
In the next tutorial, we will build custom exceptions and consistent API error responses.
#Laravel#Architecture#Advanced