All Projects → bitExpert → Adroit

bitExpert / Adroit

Licence: apache-2.0
ADR/PSR-7 middleware

Projects that are alternatives of or similar to Adroit

Funceble
[ARCHIVED] Please report to https://github.com/funilrys/PyFunceble.
Stars: ✭ 25 (-10.71%)
Mutual labels:  domain
Carter
Carter is framework that is a thin layer of extension methods and functionality over ASP.NET Core allowing code to be more explicit and most importantly more enjoyable.
Stars: ✭ 875 (+3025%)
Mutual labels:  middleware
Gentleman
Full-featured, plugin-driven, extensible HTTP client toolkit for Go
Stars: ✭ 886 (+3064.29%)
Mutual labels:  middleware
Maintenance
Site maintenance SEO PSR-15 middleware
Stars: ✭ 8 (-71.43%)
Mutual labels:  middleware
Redux Dynamic Modules
Modularize Redux by dynamically loading reducers and middlewares.
Stars: ✭ 874 (+3021.43%)
Mutual labels:  middleware
Bash Toolkit
Este proyecto esá destinado a ayudar a los sysadmin
Stars: ✭ 13 (-53.57%)
Mutual labels:  domain
Cookie Session
Simple cookie-based session middleware
Stars: ✭ 928 (+3214.29%)
Mutual labels:  middleware
Blog App Buffalo
A blogging app built with Buffalo.
Stars: ✭ 27 (-3.57%)
Mutual labels:  middleware
Disposable Email Domains
a list of disposable and temporary email address domains
Stars: ✭ 873 (+3017.86%)
Mutual labels:  domain
Grpc Tools
A suite of gRPC debugging tools. Like Fiddler/Charles but for gRPC.
Stars: ✭ 881 (+3046.43%)
Mutual labels:  middleware
Domain Status Checker
Gets ip, http return code and domain name registrar of domains
Stars: ✭ 8 (-71.43%)
Mutual labels:  domain
Outputcache
Cache api responses using Redis, Memcached or any cache provider for NodeJS
Stars: ✭ 9 (-67.86%)
Mutual labels:  middleware
Shardingsphere Elasticjob
Distributed scheduled job framework
Stars: ✭ 7,369 (+26217.86%)
Mutual labels:  middleware
Wrench
CakePHP 3 Maintenance Mode plugin
Stars: ✭ 26 (-7.14%)
Mutual labels:  middleware
Django Login Required Middleware
Requires login to all requests through middleware.
Stars: ✭ 20 (-28.57%)
Mutual labels:  middleware
Gin Stats
Gin's middleware for request stats
Stars: ✭ 24 (-14.29%)
Mutual labels:  middleware
Middlewares
💥 Middlewares / Relay / PSR-7 support to Nette Framework (@nette)
Stars: ✭ 13 (-53.57%)
Mutual labels:  middleware
Echo Logrus
echo-logrus is a middleware that provides logrus logger support for echo.
Stars: ✭ 27 (-3.57%)
Mutual labels:  middleware
Go Bootstrap
Easy way to bootstrap a web server in Go (Routing|Middleware|Https)
Stars: ✭ 27 (-3.57%)
Mutual labels:  middleware
Blazar
Pre-Render Pages on the Fly in Laravel
Stars: ✭ 14 (-50%)
Mutual labels:  middleware

bitexpert/adroit

This package provides a PSR-7 compatible ADR middleware.

Build Status Coverage Status

Installation

The preferred way of installing bitexpert/adroit is through Composer. Simply add bitexpert/adroit as a dependency:

composer.phar require bitexpert/adroit

Usage

The configure the \bitExpert\Adroit\AdroitMiddleware middleware you need provide an array of \bitExpert\Adroit\Action\Resolver\ActionResolver, an array of \bitExpert\Adroit\Responder\Resolver\ResponderResolver and a action request attribute telling adroit where to look for the action identifier.

ActionResolver

As the name implies ActionResolvers are responsible for resolving an action class instance from the so-called actionToken. The actionToken is basically used to identify a route. Adroit comes with a default implementation of an ActionResolver which uses any container-interop compatible DI container as a backend.

Of course you may implement your own ActionResolvers using the (\bitExpert\Adroit\Action\ActionResolver) interface.

/** @var \Interop\Container\ContainerInterface $container */
$actionResolver = new \bitExpert\Adroit\Action\Resolver\ContainerActionResolver($container);

ResponderResolver

Similar to the ActionResolvers the ResponderResolvers are responsible for resolving an responder class instance from the $type defined in the DomainPayload instance. Adroit comes with a default implementation of an ResponderResolver (\bitExpert\Adroit\Responder\Resolver\ContainerAwareResponderResolver) which uses any container-interop compatible DI container as a backend.

Of course you may implement your own ResponderResolvers using the ResponderResolver interface.

/** @var \Interop\Container\ContainerInterface $container */
$responderResolver = new \bitExpert\Adroit\Responder\Resolver\ContainerAwareResponderResolver($container);

(Domain)Payload

You may define your own payload class(es) by implementing the \bitExpert\Adroit\Domain\Payload interface. This gives you the opportunity to freely define the payload according to your needs. This example implementation will be used in the documentation as follows:

<?php
namespace Acme\Domain;
use bitExpert\Adroit\Domain\Payload;

class CustomPayload implements Payload
{
    protected $type;
    protected $data;

    public function __construct($type, array $data = [])
    {
        $this->type = $type;
        $this->data = $data;
    }

    public function getType()
    {
        return $this->type;
    }

    public fuction getValue($name)
    {
        return isset($this->data[$name]) ? $this->data[$name] : null;
    }
}

Actions

In case you want to implement your own action logic (who does not want that?) you may use any callable following the signature of the Action interface or create your own Action class and implement the interface.

Action classes are allowed to either return an object which implements the Payload interface or an PSR-7 response object implementing the \Psr\Http\Message\ResponseInterface interface. By default you should aim to return a Payload object. The PSR-7 response might come in handy when you have to deal with file downloads where you most likely not want to read the file in your action class, push the content to the responder just to to write it to the response message body.

<?php 
use Acme\Domain\CustomPayload;
use bitExpert\Adroit\Action\Action;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class HelloWorldAction implements Action
{
    /**
     * @inheritdoc
     */
    protected function __invoke(ServerRequestInterface $request, ResponseInterface $response)
    {
        return new CustomPayload('hello', ['name' => 'World']);
    }
}

Responders

Responders have to return a PSR-7 response object. Responders are not forced to implement the Responder interface so you may use Closures as well but implementing the interface is recommended:

<?php 
namespace Acme\Responder\HelloResponder;

use bitExpert\Adroit\Responder\Responder;
use bitExpert\Adroit\Domain\Payload;
use Psr\Http\Message\ResponseInterface;

class HelloResponder implements Responder
{
    /**
     * @inheritdoc
     */
    public function __invoke(Payload $domainPayload, ResponseInterface $response)
    {
        $response->getBody()->rewind();
        $response->getBody()->write('Hello ' . $domainPayload->getValue('name'));
        
        return $response->withStatus(200)
    }
}

Usage

Since Adroit provides a handy set of middlewares to achieve ADR you simply have to configure your ActionResolver(s) and ResponderResolver(s). For the following example we use the ArrayContainer of bitexpert/specialist which are configured using an array of mappings between the action identifier and the action and the domain payload type to the appropriate responder:

<?php
use bitExpert\Specialist\Container\ArrayContainer;

$container = new ArrayContainer([
    'helloAction' => function (ServerRequestInterface $request, ResponseInterface $response) {
        return new CustomPayload('hello', [
            'name' => 'World'
        ]);
    },
    'hello' => function (Payload $domainPayload, ResponseInterface $response) {
        $response->getBody()->rewind();
        $response->getBody()->write('Hello ' . $domainPayload->getValue('name'));
        return $response;
    };    
]);

// create the action resolver
$actionResolver = new ContainerActionResolver($container);


// create the responder resolver
$responderResolver = new ContainerResponderResolver($container);

// Provide the request attribute where the routing result identifier is kept
// and your resolvers
$adroit = new AdroitMiddleware('action', [$actionResolver], [$responderResolver]);

// create a request containing an action identifier inside the routing result attribute
$request = ServerRequestFactory::fromGlobals()->withAttribute('action', 'helloAction');

// and run adroit
$response = $adroit($request, new Response());
$emitter = new SapiEmitter();
$emitter->emit($response);

As you can see, you also may use simple callables as actions and responders.

Adroit itself does not depend on a concrete PSR-7 implementation which means you should be able to use it in your set-up without running into problems. Just for the unit tests Adroit depends on zendframework/zend-diactoros as a PSR-7 implementation.

Middleware hooks

Adroit provides several hooks to be as flexible as a standard middleware pipe while implementing the ADR paradigm.

You may use the following hooks to manipulate things in between the execution of the middlewares needed for ADR itself:

// Gets piped in front of the ActionResolverMiddleware
$adroit->beforeResolveAction($yourMiddleware);

// Gets piped in front of the ActionExecutorMiddleware
$adroit->beforeExecuteAction($yourMiddleware);

// Gets piped in front of the ResponderResolverMiddleware
$adroit->beforeResolveResponder($yourMiddleware);

// Gets piped in front of the ResponderExecutorMiddleware
$adroit->beforeExecuteResponder($yourMiddleware);

These hooks allow great flexibility but with great flexibility also comes great responsibility ;-) Please note that the hooks are named "before" and so are to implement the middlewares:

function (ServerRequestInterface $request, ResponseInterface $response, callable $next = null) {

    // Your awesome code

    if ($next)
        $response = $next($request, $response);
    }

    return $response;
}

Of course you may implement it different, but that would not hit the "before" in the hook name. Please be aware of that!

Routing

To avoid external dependencies we removed routing from Adroit since this may be achieved by using any routing mechanism you like. You just need to ensure that action identifying value will be set to a request attribute of your choice and tell the ActionMiddleware where to look for it.

License

Adroit is released under the Apache 2.0 license.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].