Building responses
A route handler decides what to return. The router accepts both plain values and HttpResponse instances, and the Responds trait provides short helpers for the common cases.
Returning plain values
A route method or closure may return any value. When the returned value is not already an HttpResponse, the router wraps it in a ResultHttpResponse automatically. This is the shortest way to answer a request with JSON-serializable data.
use Raxos\Router\Attribute\{Controller, Get};
#[Controller('/todos')]
final readonly class TodoController
{
#[Get('/')]
public function index(): array
{
return ['todos' => []];
}
}Returning a response directly
When you need control over the status code, headers or body type, return an HttpResponse instance. The router uses it as is. The Responds trait builds these for you.
<?php
declare(strict_types=1);
namespace App\Http\Controller;
use Raxos\Http\HttpResponseCode;
use Raxos\Router\Attribute\{Controller, Get, Post};
use Raxos\Router\Responds;
#[Controller('/todos')]
final readonly class TodoController
{
use Responds;
#[Get('/')]
public function index(): mixed
{
return $this->json(['todos' => []]);
}
#[Post('/')]
public function store(): mixed
{
return $this->json(['created' => true], responseCode: HttpResponseCode::CREATED);
}
}Available helpers
The Responds trait, used with use Responds;, adds a helper per common response type. Each returns an HttpResponse:
json: a JSON response.html: an HTML response.result: a generic result response, the same wrapper the router applies to plain return values.redirect: a redirect response, defaulting to status302 Found.file: a file response for a path, honoring conditional request headers.binary: a raw binary response.noContent: a204 No Contentresponse.notFound: a404 Not Foundresponse.forbidden: a403 Forbiddenresponse.error: a JSON error response for a JSON-serializable exception, using itsresponseCodewhen present.
use Raxos\Http\HttpRequest;
#[Get('/$id/download')]
public function download(HttpRequest $request, int $id): mixed
{
return $this->file("/var/todos/{$id}.pdf", $request);
}
#[Get('/redirect')]
public function toIndex(): mixed
{
return $this->redirect('/todos');
}Validation errors
Two helpers build a standardized JSON validation error response. Use validationError for a single field and constraint, and validationErrors for several at once.
#[Post('/')]
public function store(HttpRequest $request): mixed
{
if ($request->post->get('title') === null) {
return $this->validationError('title', 'required', 'A title is required.');
}
return $this->json(['created' => true]);
}