Documentation Index
Fetch the complete documentation index at: https://docs.apivalk.com/llms.txt
Use this file to discover all available pages before exploring further.
Creating a Controller
Every controller must extend AbstractApivalkController and implement four key methods:
getRoute(): Defines the path and HTTP method.
getRequestClass(): Specifies the AbstractApivalkRequest class used for this endpoint.
getResponseClasses(): Lists the possible AbstractApivalkResponse classes this controller can return.
__invoke(): The main execution logic.
Example
namespace App\Http\Controller\Pet;
use apivalk\apivalk\Http\Controller\AbstractApivalkController;
use apivalk\apivalk\Http\Request\ApivalkRequestInterface;
use apivalk\apivalk\Http\Response\AbstractApivalkResponse;
use apivalk\apivalk\Router\Route\Route;
use apivalk\apivalk\Http\Method\GetMethod;
use App\Http\Request\Pet\GetPetRequest;
use App\Http\Response\Pet\GetPetResponse;
use App\Http\Response\Common\NotFoundResponse;
class GetPetController extends AbstractApivalkController
{
public static function getRoute(): Route
{
return new Route('/pet/{id}', new GetMethod());
}
public static function getRequestClass(): string
{
return GetPetRequest::class;
}
public static function getResponseClasses(): array
{
return [
GetPetResponse::class,
NotFoundResponse::class,
];
}
public function __invoke(ApivalkRequestInterface $request): AbstractApivalkResponse
{
// $request is already populated and validated!
$id = $request->path()->id;
// Access populated sorting filters. SortBag is iterable — iterate
// directly. The bag is always populated: if the user does not provide
// order_by, it contains the default sorting from the route.
foreach ($request->sorting() as $field => $sort) {
$direction = $sort->isAsc() ? 'ASC' : 'DESC';
}
// or directly access populated filters.
// If the user did not pass order_by=+status or -status, the magic getter returns
// the default Sort object for status if it was defined on the route.
$isAsc = $request->sorting()->status->isAsc();
$pet = $this->petRepository->find($id);
if (!$pet) {
return new NotFoundResponse('Pet not found');
}
return new GetPetResponse($pet);
}
}
Dependency Injection
If you configured a PSR-11 container, you can use constructor injection:
public function __construct(PetRepository $petRepository)
{
$this->petRepository = $petRepository;
}
Route Discovery
Apivalk uses ClassLocator to scan your controller directory. You don’t need to register routes manually; the framework discovers them automatically by calling getRoute() on any class extending AbstractApivalkController.
For endpoints returning lists of data, see the Pagination guide.
Resource Controllers (CRUD)
If your endpoint follows a standard RESTful CRUD pattern against a single entity, you don’t need to author a controller class like the one above by hand. Apivalk ships five abstract base controllers — AbstractCreateResourceController, AbstractViewResourceController, AbstractUpdateResourceController, AbstractDeleteResourceController, AbstractListResourceController — that derive their route, request class, response classes, and OpenAPI documentation from an AbstractResource declaration.
A minimal list controller looks like this:
use apivalk\apivalk\Http\Controller\Resource\AbstractListResourceController;
use App\Resource\AnimalResource;
/**
* @extends AbstractListResourceController<AnimalResource>
*/
final class ListAnimalController extends AbstractListResourceController
{
public static function getResourceClass(): string
{
return AnimalResource::class;
}
public function __invoke(ApivalkRequestInterface $request): AbstractApivalkResponse
{
// fetch, paginate, return ResourceListResponse
}
}
See the full Resources section for how to declare a resource and wire up all five CRUD endpoints.