Responses
The Response class wraps HTTP responses with typed accessors and convenience methods for parsing, validation, and transformation.
Basic Response Handling
Section titled “Basic Response Handling”$response = $connector->send(new GetUserRequest(1));Status Checking
Section titled “Status Checking”$status = $response->status(); // 200, 404, 500, etc.
$response->ok(); // true if 2xx$response->successful(); // alias for ok()$response->redirect(); // true if 3xx$response->clientError(); // true if 4xx$response->serverError(); // true if 5xx$response->failed(); // true if 4xx or 5xxParsing Response Body
Section titled “Parsing Response Body”As JSON Array
Section titled “As JSON Array”$data = $response->json();$name = $response->json('user.name');$email = $response->json('data.0.email');$role = $response->json('user.role') ?? 'guest';As Object
Section titled “As Object”$object = $response->object();echo $object->name;As Collection
Section titled “As Collection”$collection = $response->collect();$users = $response->collect('data.users');
$activeUsers = $response->collect('users') ->where('active', true) ->pluck('email');As Raw String
Section titled “As Raw String”$body = $response->body();Mapping to DTOs
Section titled “Mapping to DTOs”Single DTO
Section titled “Single DTO”class User{ public function __construct( public readonly int $id, public readonly string $name, public readonly string $email, ) {}}
$user = $response->dto(User::class);Collection of DTOs
Section titled “Collection of DTOs”$users = $response->dtoCollection(User::class);$users = $response->dtoCollection(User::class, 'data.users');Headers
Section titled “Headers”$contentType = $response->header('Content-Type');$rateLimit = $response->header('X-RateLimit-Remaining');$headers = $response->headers();Error Handling
Section titled “Error Handling”Throw on Failure
Section titled “Throw on Failure”$response->throw(); // Throws if 4xx or 5xx
$data = $response->throw()->json();Check Before Processing
Section titled “Check Before Processing”if ($response->failed()) { $error = $response->json('error.message'); throw new ApiException($error, $response->status());}Conditional Requests
Section titled “Conditional Requests”$etag = $response->etag();$lastModified = $response->lastModified();
if ($response->wasNotModified()) { // Use cached version}Caching Information
Section titled “Caching Information”if ($response->fromCache()) { // Response was served from cache}Timing
Section titled “Timing”$durationMs = $response->duration();Rate Limit Information
Section titled “Rate Limit Information”$rateLimit = $response->rateLimit();
if ($rateLimit) { echo $rateLimit->limit; echo $rateLimit->remaining; echo $rateLimit->reset;}Tracing
Section titled “Tracing”$traceId = $response->traceId();$spanId = $response->spanId();Idempotency
Section titled “Idempotency”$key = $response->idempotencyKey();
if ($response->wasIdempotentReplay()) { // This response was a replay}File Downloads
Section titled “File Downloads”Save to File
Section titled “Save to File”$response->saveTo('/path/to/file.pdf');Stream with Progress
Section titled “Stream with Progress”$response->streamTo('/path/to/large-file.zip', function ($downloaded, $total) { $percent = $total > 0 ? ($downloaded / $total) * 100 : 0; echo "Downloaded: {$percent}%\n";});Get Filename
Section titled “Get Filename”$filename = $response->filename();
if ($response->isDownload()) { $response->saveTo('/downloads/' . $response->filename());}Get as Base64
Section titled “Get as Base64”$base64 = $response->base64();Iterate Chunks
Section titled “Iterate Chunks”foreach ($response->chunks(8192) as $chunk) { fwrite($handle, $chunk);}Get as Stream
Section titled “Get as Stream”$stream = $response->stream();Response Transformation
Section titled “Response Transformation”Modify JSON Body
Section titled “Modify JSON Body”$newResponse = $response->withJson(['modified' => true]);$newResponse = $response->withJsonKey('processed_at', now()->toIso8601String());Modify Raw Body
Section titled “Modify Raw Body”$newResponse = $response->withBody('new raw content');Modify Headers
Section titled “Modify Headers”$newResponse = $response->withHeaders(['X-Custom' => 'value']);$newResponse = $response->withHeader('X-Custom', 'value');Modify Status
Section titled “Modify Status”$newResponse = $response->withStatus(201);Accessing Original Request
Section titled “Accessing Original Request”$request = $response->request();echo $request->endpoint();echo $request->method();PSR-7 Response
Section titled “PSR-7 Response”$psrResponse = $response->toPsrResponse();Creating Responses
Section titled “Creating Responses”use Cline\Relay\Core\Response;
$response = Response::make( data: ['id' => 1, 'name' => 'John'], status: 200, headers: ['X-Custom' => 'value'],);
$response->json('name'); // 'John'$response->status(); // 200Debugging
Section titled “Debugging”$response->dump(); // Dump and continue$response->dd(); // Dump and dieMacros
Section titled “Macros”use Cline\Relay\Core\Response;
Response::macro('isRateLimited', function () { return $this->status() === 429;});
if ($response->isRateLimited()) { $retryAfter = $response->header('Retry-After'); sleep((int) $retryAfter);}Full Example
Section titled “Full Example”$response = $connector->send(new GetOrderRequest($orderId));
if ($response->failed()) { if ($response->status() === 404) { throw new OrderNotFoundException($orderId); }
throw new ApiException( $response->json('error.message'), $response->status() );}
logger()->info('API call completed', [ 'duration' => $response->duration(), 'cached' => $response->fromCache(), 'trace_id' => $response->traceId(),]);
$rateLimit = $response->rateLimit();if ($rateLimit && $rateLimit->remaining < 10) { logger()->warning('Rate limit running low', [ 'remaining' => $rateLimit->remaining, 'reset' => $rateLimit->reset, ]);}
$order = $response->dto(Order::class);$items = $response->dtoCollection(OrderItem::class, 'items');
if ($response->json('has_attachment')) { $attachmentResponse = $connector->send(new GetOrderAttachmentRequest($orderId));
if ($attachmentResponse->isDownload()) { $attachmentResponse->saveTo( storage_path('orders/' . $attachmentResponse->filename()) ); }}