Skip to main content

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:
  1. getRoute(): Defines the path and HTTP method.
  2. getRequestClass(): Specifies the AbstractApivalkRequest class used for this endpoint.
  3. getResponseClasses(): Lists the possible AbstractApivalkResponse classes this controller can return.
  4. __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.

Pagination

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.