Skip to content

apivalk/apivalk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

95 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

apivalk

apivalk πŸ¦…

Packagist Version PHP License Docs

OpenAPI-first PHP framework for type-safe REST APIs. Framework-agnostic Β· PSR-7/15/11/3 Β· PHP 7.2+


The Problem

OpenAPI specs drift from code. $_POST['name'] has no type. Nobody knows which endpoints are secured. You maintain two things β€” the code and the docs β€” and they never quite agree.

apivalk makes your PHP classes the single source of truth. Define a property once β†’ automatic validation, type casting, OpenAPI 3.0 generation, and full IDE autocompletion.


Why apivalk? πŸ€”

  • πŸ“„ Code is the spec β€” getDocumentation() on your request/response classes drives validation, type casting, and OpenAPI generation from one definition. No annotation parsing, no separate YAML.
  • πŸ” Zero route registration β€” drop a controller into your directory. ClassLocator auto-discovers it and caches the route index. No config files to update.
  • ⚑ Resource CRUD β€” one AbstractResource declaration generates five typed CRUD endpoints with full OpenAPI coverage. ~15 hand-authored classes collapse into one resource + five thin controllers.
  • πŸ”’ Security built in β€” JWT (JWK-based), scope enforcement, and three route security levels out of the box.
  • 🧠 Typed everything β€” by the time __invoke() runs, input is sanitized, validated, and cast. You get $request->body()->name, not $_POST['name'].
  • πŸ’‘ Full IDE autocompletion β€” DocBlockGenerator rewrites your request classes with typed @method annotations and generates Shape/ classes per bag. $request->body()->, $request->sorting()->, $request->filtering()-> all autocomplete with correct types in PhpStorm and VS Code β€” zero hand-written boilerplate.

Installation

composer require apivalk/apivalk

PHP 7.2+, ext-json, ext-mbstring β€” full installation guide β†’


Quick Start

Bootstrap

<?php
declare(strict_types=1);

use apivalk\apivalk\Apivalk;
use apivalk\apivalk\ApivalkConfiguration;
use apivalk\apivalk\ApivalkExceptionHandler;
use apivalk\apivalk\Cache\FilesystemCache;
use apivalk\apivalk\Middleware\RequestValidationMiddleware;
use apivalk\apivalk\Middleware\SanitizeMiddleware;
use apivalk\apivalk\Router\Router;
use apivalk\apivalk\Util\ClassLocator;

require __DIR__ . '/vendor/autoload.php';

$classLocator = new ClassLocator(__DIR__ . '/src/Http/Controller', 'App\\Http\\Controller');
$router = new Router($classLocator, new FilesystemCache(__DIR__ . '/var/cache'));

$configuration = new ApivalkConfiguration(
    $router,
    null,                                        // default: JsonRenderer
    [ApivalkExceptionHandler::class, 'handle']
);

$configuration->getMiddlewareStack()->add(new SanitizeMiddleware());
$configuration->getMiddlewareStack()->add(new RequestValidationMiddleware());

$apivalk = new Apivalk($configuration);
$response = $apivalk->run();
$apivalk->getRenderer()->render($response);

Every controller in src/Http/Controller is auto-discovered on first boot and cached. No routes to register. β†’ Configure Apivalk

Define an Endpoint

Every endpoint is a Controller + Request + Response triplet. The Request defines the shape β€” it drives validation and OpenAPI. The Response defines the output schema.

// Controller β€” owns the route and the business logic
final class ReadPetController extends AbstractApivalkController
{
    public static function getRoute(): Route
    {
        return Route::get('/v1/pets/{id}')->description('Get a pet by ID');
    }

    public static function getRequestClass(): string  { return ReadPetRequest::class; }
    public static function getResponseClasses(): array { return [ReadPetResponse::class, NotFoundApivalkResponse::class]; }

    public function __invoke(ApivalkRequestInterface $request): AbstractApivalkResponse
    {
        $pet = $this->petRepo->find($request->path()->id); // id is cast to int automatically
        return $pet ? new ReadPetResponse($pet) : new NotFoundApivalkResponse('Pet not found');
    }
}

// Request β€” declares the input shape; drives validation + OpenAPI
class ReadPetRequest extends AbstractApivalkRequest
{
    public static function getDocumentation(): ApivalkRequestDocumentation
    {
        $doc = new ApivalkRequestDocumentation();
        $doc->addPathProperty(new IntegerProperty('id', 'Pet ID'));
        return $doc;
    }
}

// Response β€” declares the output shape; drives OpenAPI schema
class ReadPetResponse extends AbstractApivalkResponse
{
    public static function getStatusCode(): int { return self::HTTP_200_OK; }

    public static function getDocumentation(): ApivalkResponseDocumentation
    {
        $doc = new ApivalkResponseDocumentation();
        $doc->addProperty(new IntegerProperty('id', 'Pet ID'));
        $doc->addProperty(new StringProperty('name', 'Pet name'));
        return $doc;
    }

    public function toArray(): array { return ['id' => $this->pet['id'], 'name' => $this->pet['name']]; }
}

RequestValidationMiddleware returns 422 with field-level errors automatically. β†’ Controllers Β· Requests Β· Responses


Features

πŸ›£οΈ Routing

Auto-discovery, filesystem route caching, fluent builder (Route::get/post/put/patch/delete), automatic 404/405 handling, path parameters via {name} syntax. β†’ Routing docs

πŸ’‘ IDE Autocompletion via DocBlock Generator

Run DocBlockGenerator once (or as a CI step) and your request classes get full IDE support β€” no hand-written boilerplate.

Before:

class ReadPetRequest extends AbstractApivalkRequest { /* empty */ }

After (auto-generated):

/**
 * @method ParameterBag|Shape\ReadPetPathShape path()
 * @method ParameterBag|Shape\ReadPetBodyShape body()
 * @method SortBag|Shape\ReadPetSortingShape sorting()
 * @method FilterBag|Shape\ReadPetFilteringShape filtering()
 * @method Paginator|null paginator()
 */
class ReadPetRequest extends AbstractApivalkRequest { /* still empty */ }

$request->path()->id, $request->body()->name, $request->sorting()->createdAt β€” all autocomplete with their correct types. Works for resource controllers too: DocBlockGenerator emits @property annotations on AbstractResource subclasses and generates typed list request classes (AnimalListRequest) with fully wired sort/filter/paginator shapes.

$generator = new DocBlockGenerator();
$generator->run('/src/Http/Controller', 'App\\Http\\Controller');

β†’ DocBlock generator docs Β· Generate how-to

πŸ§… Middleware Pipeline

Onion-style PSR-15 pipeline. Built in: SanitizeMiddleware, RequestValidationMiddleware, AuthenticationMiddleware, SecurityMiddleware, RateLimitMiddleware. Trivial to extend with your own. β†’ Middleware docs Β· Custom middleware

πŸ”’ Security & Authorization

Three route security levels β€” public, authenticated-only, scoped. JwtAuthenticator supports JWK endpoints out of the box. Missing scope β†’ 403 Forbidden. No token β†’ 401 Unauthorized. Custom authenticators supported via AuthenticatorInterface. β†’ Security docs Β· JWT how-to Β· API key how-to

πŸ“„ OpenAPI 3.0 Generation

OpenAPIGenerator introspects every controller's request and response classes and emits a complete OpenAPI 3.0 spec β€” including pagination envelopes, X-RateLimit-* headers, locale headers, and per-operation security requirements. No annotations. Run it as a bin/ script and drop the JSON behind Swagger UI. β†’ OpenAPI generator Β· Generate how-to

πŸ“¦ Resource CRUD

Declare an AbstractResource once β€” identifier, properties, filters, sortings β€” and get five fully typed, validated, OpenAPI-documented CRUD endpoints with matching response envelopes. Only __invoke() is yours to write. β†’ Resources Β· Resource CRUD how-to

πŸ“ƒ Pagination

Three strategies per route: Pagination::page(), Pagination::offset(), Pagination::cursor(). apivalk handles query param validation, paginator hydration, and JSON envelope (data + pagination). All shapes documented in OpenAPI automatically. β†’ Pagination docs Β· Pagination how-to

πŸ”’ Sorting & Filtering

Declare allowed sort fields and filter types on the route. Sorting defaults are applied when order_by is omitted β€” $request->sorting() is always populated. Undeclared filter keys are silently ignored. β†’ Sorting Β· Filtering

⏱️ Rate Limiting

Per-route IP-based rate limiting. X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset on every response; Retry-After on 429. Documented in OpenAPI automatically. β†’ Rate limiting

🌍 Localization

Locale resolved from Accept-Language on every request, Content-Language set on every response. Both headers documented in OpenAPI. Zero boilerplate in controllers. β†’ Localization docs

βš™οΈ Dependency Injection

Pass any PSR-11 container β€” PHP-DI, Symfony DI, or your own. Apivalk uses it to resolve controllers, enabling full constructor injection. Without a container it falls back to new ControllerClass(). β†’ Configuration


Built-in Error Responses

BadRequestApivalkResponse (400) Β· UnauthorizedApivalkResponse (401) Β· ForbiddenApivalkResponse (403) Β· NotFoundApivalkResponse (404) Β· MethodNotAllowedApivalkResponse (405) Β· BadValidationApivalkResponse (422) Β· TooManyRequestsApivalkResponse (429) Β· InternalServerErrorApivalkResponse (500)


Contributing & Local Development

make build || docker compose build
make composer || docker compose run --rm php72 composer install
make test || docker compose run --rm php72 composer test-unit && docker compose run --rm php72 composer test-integration # PHPUnit unit & integration test suite
make phpstan || docker compose run --rm php72 composer phpstan # PHPStan
make ci # will run composer, test and phpstan

Own PHP 7.2+ setup? Docker is optional β€” DDEV, Lando, or native all work. PHPStan runs at level 6; new code must not add violations (a baseline covers pre-existing issues). β†’ Contributing guide


πŸ“š docs.apivalk.com Β· 🌐 apivalk.com Β· πŸ› * Issues*

Β© 2025 apivalk. MIT License. Maintainer: Dominic Poppe.

About

A Lightweight, Framework-Agnostic REST API Ecosystem for PHP. Built for speed, precision, and type-safe development.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors

Languages