Contributte Apitte
for transformations of response after it is returned from endpoint.
They could e.g. add some useful data, transform them or handle request globally (e.g. for authorization).
# Setup
api:
plugins:
Apitte\Core\DI\Plugin\CoreDecoratorPlugin:
2
3
Decorator plugin overrides JsonDispatcher with DecoratedDispatcher
# Register decorators
services:
decorator.request.authentication:
class: App\Api\Decorator\ExampleResponseDecorator
tags: [apitte.core.decorator: [priority: 50]]
2
3
4
Each decorator could have tag apitte.core.decorator
with priority
defined.
- Decorator with lowest
priority
number is called first. - Default
priority
is 10
# Request decorators
Add some data to request or return response through EarlyReturnResponseException
.
# RequestParameterDecorator and RequestEntityDecorator
Enable mapping of request parameters and entities.
Registered with priorities 100
and 101
.
See mapping chapter for more info.
# Implementing request decorator
# MetadataDecorator
services:
decorator.request.metadata:
class: App\Api\Decorator\RequestMetadataDecorator
tags: [apitte.core.decorator: [priority: 50]
2
3
4
namespace App\Api\Decorator;
use Apitte\Core\Decorator\IRequestDecorator;
use Apitte\Core\Exception\Runtime\EarlyReturnResponseException;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
class RequestMetadataDecorator implements IRequestDecorator
{
/**
* @throws EarlyReturnResponseException If other request decorators and also deeper layers (endpoint) should be skipped
*/
public function decorateRequest(ApiRequest $request, ApiResponse $response): ApiRequest
{
// Do something with request (e.g. add useful attributes for endpoint)
$request = $request->withAttribute('attributeName', 'attributeValue');
return $request;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# AuthenticationDecorator
services:
decorator.request.authentication:
class: App\Api\Decorator\RequestAuthenticationDecorator
tags: [apitte.core.decorator: [priority: 1, type: handler.before]]
2
3
4
namespace App\Api\Decorator;
use Apitte\Core\Decorator\IRequestDecorator;
use Apitte\Core\Exception\Runtime\EarlyReturnResponseException;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use GuzzleHttp\Psr7\Utils;
class RequestAuthenticationDecorator implements IRequestDecorator
{
/**
* @throws EarlyReturnResponseException If other request decorators and also deeper layers (endpoint) should be skipped
*/
public function decorateRequest(ApiRequest $request, ApiResponse $response): ApiRequest
{
if ($userAuthenticationFailed) {
$body = Utils::streamFor(json_encode([
'status' => 'error',
'code' => 403,
'message' => 'Invalid credentials, authentication failed.'
]));
$response = $response
->withStatus(403)
->withBody($body);
throw new EarlyReturnResponseException($response);
}
return $request;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Tip
You could also authenticate only some endpoints thanks to tags and metadata from SimpleRouter
.
use Apitte\Core\Http\RequestAttributes;
use Apitte\Core\Schema\Endpoint;
/** @var Endpoint $endpoint Schema of matched endpoint */
$endpoint = $request->getAttribute(RequestAttributes::ATTR_ENDPOINT);
if ($endpoint->hasTag('noAuthentication')) {
// Don't authenticate
}
2
3
4
5
6
7
8
9
# Response decorators
Modify response returned from endpoint.
You could return response through EarlyReturnResponseException
so other response decorators are not used.
# ResponseEntityDecorator
Transforms data into format requested in Accept
header and in url suffix (/api/v1/users.xml
)
See negotiation chapter for details.
# Implementing response decorator
namespace App\Api\Decorator;
use Apitte\Core\Decorator\IResponseDecorator;
use Apitte\Core\Exception\Runtime\EarlyReturnResponseException;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
class ExampleResponseDecorator implements IResponseDecorator
{
/**
* @throws EarlyReturnResponseException If other response decorators should be skipped
*/
public function decorateResponse(ApiRequest $request, ApiResponse $response): ApiResponse
{
// Do something with response (e.g. transform data)
return $response;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Exception decorators
Transforms error into response.
If an exception decorator return null instead of response then error is handled by internal error handler
# ResponseEntityDecorator
Transforms error into format requested in Accept
header and in url suffix (/api/v1/users.xml
)
See negotiation chapter for details.
# Implementing exception decorator
namespace App\Api\Decorator;
use Apitte\Core\Decorator\IErrorDecorator;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use Throwable;
class ExampleExceptionDecorator implements IErrorDecorator
{
public function decorateError(ApiRequest $request, ApiResponse $response, Throwable $error): ApiResponse
{
$response = $this->errorToResponse($response, $error);
return $response;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18