labrador-kennel / http
A framework for building asynchronous applications with Amp and Annotated Container.
Requires
- php: ~7.2
- ext-json: *
- amphp/file: ^1.0
- amphp/http-server: ~2.0.0-rc2
- cspray/labrador: ~3.0.0-beta7
- cspray/labrador-async-event: 2.0.0-rc1
- league/uri-schemes: ~1.2
- monolog/monolog: ^1.24
- nikic/fast-route: ~1.3
Requires (Dev)
- amphp/http-client: ^4.0.0-rc7
- amphp/phpunit-util: ^1.2
- cspray/labrador-coding-standard: 0.1.0
- phpunit/phpunit: ~7
This package is auto-updated.
Last update: 2024-11-03 19:32:05 UTC
README
Labrador HTTP is a framework for creating feature-rich, SOLID web applications. It is primarily a set of opinions on integrating the following libraries:
- amphp/http-server Provides the underlying server and HTTP-stack.
- cspray/annotated-container Provides a powerful dependency injection framework using PHP 8 Attributes.
- nikic/fast-route Provides the actual routing functionality that maps a Request to a Controller.
- cuyz/valinor Provides the ability to create DTO objects from a Request body.
This is not meant to be an exhaustive list of all dependencies, simply those involving major integration points.
Please check out the Quick Start below for more details on Labrador HTTP's novel features.
Install
Use Composer to install the library.
composer require cspray/labrador-http:dev-main
Quick Start
Labrador's most novel feature is its integration with Annotated Container to allow the following features:
- Inject specific parts of a Request into a controller method
- Inject custom DTO objects based on a JSON encoded body
- Specify route mapping using FastRoute and Attributes.
It's best to show a Controller implementing this functionality.
<?php declare(strict_types=1); namespace LabradorDemo; use Amp\Http\Server\Response;use Labrador\Web\Controller\Dto\Dto;use Labrador\Web\Controller\Dto\RouteParam;use Labrador\Web\Controller\RouteMapping\ControllerActions;use Labrador\Web\Controller\RouteMapping\Get;use Labrador\Web\Controller\RouteMapping\Post;use League\Uri\Components\Query;use Psr\Log\LoggerInterface;use Ramsey\Uuid\UuidInterface; #[ControllerActions] final class WidgetController { // The $logger will be a Monolog logger that sends output to stdout using amphp/log public function __construct( private readonly LoggerInterface $logger ) {} // The $filter will be injected from the query parameters sent in the request // The $widgetGatherer is an injected service and will be the same instance, unlike $filter #[Get('/widgets')] public function list(Query $filter, WidgetGatherer $widgetGatherer) : Response { // do some stuff to generate a response } // The $widgetId will be injected from the value sent in the route // The $widgetGatherer is an injected service and will be the same instance, unlike $widgetId #[Get('/widgets/{id}')] public function fetch(#[RouteParam('id')] UuidInterface $widgetId, WidgetGatherer $widgetGatherer) : Response { // do some stuff to generate a response } // The $widget will be created using cuyz/valinor from the JSON decoded Request body // The $creator is an injected service and will be the same instance, unlike $widget #[Post('/widgets')] public function create(#[Dto] Widget $widget, WidgetCreator $creator) : Response { // do some stuff to generate a response } }
Request Injections
Labrador HTTP also provides the ability to get specific parts of the Request using a set of Attributes, or specific type mappings.
<?php declare(strict_types=1); namespace LabradorDemo; use Amp\Http\Server\RequestBody;use Amp\Http\Server\Response;use Labrador\Controller\Dto\QueryParams;use Labrador\Controller\Dto\Url;use Labrador\Web\Controller\Dto\Body;use Labrador\Web\Controller\Dto\Header;use Labrador\Web\Controller\Dto\Headers;use Labrador\Web\Controller\Dto\Method;use Labrador\Web\Controller\Dto\RouteParam;use Labrador\Web\Controller\RouteMapping\ControllerActions;use Labrador\Web\Controller\RouteMapping\Get;use Labrador\Web\Controller\RouteMapping\Post;use League\Uri\Components\Query;use League\Uri\Contracts\QueryInterface;use Psr\Http\Message\UriInterface; #[ControllerActions] class RequestInjectionController { #[Get('/headers')] public function headers(#[Headers] array $headers) : Response { // ... } #[Get('/header-array')] public function headerAsArray(#[Header('Accept')] array $accept) : Response { // ... } #[Get('/header-string')] public function headerAsString(#[Header('Authorization')] string $token) : Response { // ... } #[Get('/url/attr')] public function url(#[Url] UriInterface $uri) : Response { // ... } #[Get('/method')] public function method(#[Method] string $method) : Response { // ... } #[Get('/body/buffered')] public function body(#[Body] string $body) : Response { // ... } #[Post(('/body/stream'))] public function bodyStream(#[Body] RequestBody $body) : Response { // ... } #[Get('/query/string')] public function queryAsString(#[QueryParams] string $query) : Response { // ... } #[Get('/query/interface')] public function queryAsInterface(#[QueryParams] QueryInterface $query) : Response { // ... } #[Get('/query/object')] public function queryAsObject(#[QueryParams] Query $query) : Response { // ... } #[Get('/route/{foo}/param/{bar}')] public function routeParam( #[RouteParam('foo')] string $fooParam, #[RouteParam('bar')] string $barParam ) : Response { // ... } // Some parameters you can simply provide a type and not have to attribute it #[Get('/uri/implied')] public function uriImplied(UriInterface $uri) : Response { // ... } #[Get('/query/implied')] public function queryImplied(Query $query) : Response { // ... } #[Get('/body/implied')] public function bodyImplied(RequestBody $body) : Response { // ... } }