Response macros — adding custom response methods globally
Concept
Response macros and custom response classes allow extending Laravel's response system to enforce consistent API response formatting across an application.
Response::macro(string $name, callable $macro): Adds a method to all Response instances. Defined in AppServiceProvider::boot(). Available on both the response() helper and Response facade.
Responsable interface: Any class implementing Illuminate\Contracts\Support\Responsable can be returned directly from controllers. Laravel calls toResponse(Request $request) on it and uses the result as the HTTP response. This enables rich response objects that carry both data and HTTP semantics.
Custom JSON Resource responses: API Resources (covered in lv-24) extend JsonResource and implement Responsable. Returning new UserResource($user) from a controller automatically returns a JSON response.
Standard API response pattern: Many teams define a consistent envelope: {'success': bool, 'data': mixed, 'message': string}. Implement via a macro or a ApiResponse class.
Response tapping: ->withCallback(callable $callback) (JSONP), ->setCallback(). Less commonly used.
Streaming responses: response()->stream(callable $callback, int $status, array $headers) — sends chunked transfer encoding for server-sent events or streaming data.
Code Example
<?php
// AppServiceProvider::boot()
use Illuminate\Support\Facades\Response;
// API response macros
Response::macro('success', function(mixed $data = null, string $message = 'Success', int $status = 200) {
return response()->json([
'success' => true,
'message' => $message,
'data' => $data,
], $status);
});
Response::macro('error', function(string $message, int $status = 400, array $errors = []) {
return response()->json(array_filter([
'success' => false,
'message' => $message,
'errors' => $errors ?: null,
]), $status);
});
Response::macro('paginated', function(\Illuminate\Pagination\LengthAwarePaginator $paginator) {
return response()->json([
'success' => true,
'data' => $paginator->items(),
'meta' => [
'total' => $paginator->total(),
'per_page' => $paginator->perPage(),
'current_page' => $paginator->currentPage(),
'last_page' => $paginator->lastPage(),
],
]);
});
// Usage in controllers
return response()->success($user, 'User created', 201);
return response()->error('Validation failed', 422, $errors);
return response()->paginated(User::paginate(15));
// Responsable interface — return custom objects from controllers
class OrderSummaryResponse implements \Illuminate\Contracts\Support\Responsable
{
public function __construct(private readonly Order $order) {}
public function toResponse($request): \Illuminate\Http\Response
{
return response()->json([
'order' => new OrderResource($this->order),
'totals' => $this->order->calculateTotals(),
'timeline' => $this->order->getTimeline(),
]);
}
}
// Controller returns the Responsable object directly
public function show(Order $order): OrderSummaryResponse
{
return new OrderSummaryResponse($order);
}