API: Moved json handling and route-api tagging to ApiRouteHandler
This commit is contained in:
parent
8adad075bf
commit
e2e18db460
|
@ -28,7 +28,6 @@ return [
|
||||||
\Engelsystem\Renderer\TwigServiceProvider::class,
|
\Engelsystem\Renderer\TwigServiceProvider::class,
|
||||||
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
||||||
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
||||||
\Engelsystem\Middleware\SessionHandlerServiceProvider::class,
|
|
||||||
\Engelsystem\Http\Validation\ValidationServiceProvider::class,
|
\Engelsystem\Http\Validation\ValidationServiceProvider::class,
|
||||||
\Engelsystem\Http\RedirectServiceProvider::class,
|
\Engelsystem\Http\RedirectServiceProvider::class,
|
||||||
|
|
||||||
|
@ -54,6 +53,7 @@ return [
|
||||||
|
|
||||||
// The application code
|
// The application code
|
||||||
\Engelsystem\Middleware\ErrorHandler::class,
|
\Engelsystem\Middleware\ErrorHandler::class,
|
||||||
|
\Engelsystem\Middleware\ApiRouteHandler::class,
|
||||||
\Engelsystem\Middleware\VerifyCsrfToken::class,
|
\Engelsystem\Middleware\VerifyCsrfToken::class,
|
||||||
\Engelsystem\Middleware\RouteDispatcher::class,
|
\Engelsystem\Middleware\RouteDispatcher::class,
|
||||||
\Engelsystem\Middleware\SessionHandler::class,
|
\Engelsystem\Middleware\SessionHandler::class,
|
||||||
|
|
|
@ -32,12 +32,31 @@ components:
|
||||||
bearerFormat: API key from settings
|
bearerFormat: API key from settings
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
UnauthorizedError:
|
UnauthorizedError: # 401
|
||||||
description: Access token is missing or invalid
|
description: Access token is missing or invalid
|
||||||
ForbiddenError:
|
content:
|
||||||
description: The client is not allowed to acces
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
ForbiddenError: # 403
|
||||||
|
description: The client is not allowed to access
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
NotImplementedError: # 501
|
||||||
|
description: This endpoint or method is not implemented
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
|
||||||
schemas:
|
schemas:
|
||||||
|
Error:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
News:
|
News:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -42,7 +42,7 @@ class Authenticator
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->user = $this->userFromSession();
|
$this->user = $this->userFromSession();
|
||||||
if (!$this->user && request()->getAttribute('route-api', false)) {
|
if (!$this->user && request()->getAttribute('route-api-accessible', false)) {
|
||||||
$this->user = $this->userFromApi();
|
$this->user = $this->userFromApi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Middleware;
|
||||||
|
|
||||||
|
use Engelsystem\Exceptions\Handler;
|
||||||
|
use Engelsystem\Http\Exceptions\HttpException;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Nyholm\Psr7\Stream;
|
||||||
|
use Nyholm\Psr7\Uri;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ApiRouteHandler implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected ?string $apiPrefix = '/api',
|
||||||
|
protected ?array $apiAccessiblePaths = [
|
||||||
|
'/atom',
|
||||||
|
'/rss',
|
||||||
|
'/health',
|
||||||
|
'/ical',
|
||||||
|
'/metrics',
|
||||||
|
'/shifts-json-export',
|
||||||
|
'/stats',
|
||||||
|
]
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the incoming request and handling API responses
|
||||||
|
*/
|
||||||
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
|
{
|
||||||
|
$path = (new Uri((string) $request->getUri()))->getPath();
|
||||||
|
if ($request instanceof Request) {
|
||||||
|
$path = $request->getPathInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = urldecode($path);
|
||||||
|
$isApi = $this->apiPrefix && (Str::startsWith($path, $this->apiPrefix . '/') || $path == $this->apiPrefix);
|
||||||
|
$isApiAccessible = $isApi || $this->apiAccessiblePaths && in_array($path, $this->apiAccessiblePaths);
|
||||||
|
$request = $request
|
||||||
|
->withAttribute('route-api', $isApi)
|
||||||
|
->withAttribute('route-api-accessible', $isApiAccessible);
|
||||||
|
|
||||||
|
return $isApi ? $this->processApi($request, $handler) : $handler->handle($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the API request by ensuring that JSON is returned
|
||||||
|
*/
|
||||||
|
protected function processApi(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = $handler->handle($request);
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
$response = new Response('', 404);
|
||||||
|
$response->setContent($response->getReasonPhrase());
|
||||||
|
} catch (HttpException $e) {
|
||||||
|
$response = new Response($e->getMessage(), $e->getStatusCode(), $e->getHeaders());
|
||||||
|
$response->setContent($response->getContent() ?: $response->getReasonPhrase());
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
/** @var Handler $handler */
|
||||||
|
$handler = app('error.handler');
|
||||||
|
$handler->exceptionHandler($e, true);
|
||||||
|
$response = new Response('', 500);
|
||||||
|
$response->setContent($response->getReasonPhrase());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Str::isJson((string) $response->getBody())) {
|
||||||
|
$content = (string) $response->getBody();
|
||||||
|
$content = Stream::create(json_encode([
|
||||||
|
'message' => $content,
|
||||||
|
]));
|
||||||
|
$response = $response
|
||||||
|
->withHeader('content-type', 'application/json')
|
||||||
|
->withBody($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
$eTag = md5((string) $response->getBody());
|
||||||
|
$response->setEtag($eTag);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,8 +14,6 @@ use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
|
||||||
class RouteDispatcher implements MiddlewareInterface
|
class RouteDispatcher implements MiddlewareInterface
|
||||||
{
|
{
|
||||||
protected ?MiddlewareInterface $notFound = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ResponseInterface $response Default response
|
* @param ResponseInterface $response Default response
|
||||||
* @param MiddlewareInterface|null $notFound Handles any requests if the route can't be found
|
* @param MiddlewareInterface|null $notFound Handles any requests if the route can't be found
|
||||||
|
@ -23,9 +21,8 @@ class RouteDispatcher implements MiddlewareInterface
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected FastRouteDispatcher $dispatcher,
|
protected FastRouteDispatcher $dispatcher,
|
||||||
protected ResponseInterface $response,
|
protected ResponseInterface $response,
|
||||||
MiddlewareInterface $notFound = null
|
protected ?MiddlewareInterface $notFound = null
|
||||||
) {
|
) {
|
||||||
$this->notFound = $notFound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Engelsystem\Middleware;
|
namespace Engelsystem\Middleware;
|
||||||
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Server\MiddlewareInterface;
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
@ -14,26 +13,21 @@ use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
|
||||||
|
|
||||||
class SessionHandler implements MiddlewareInterface
|
class SessionHandler implements MiddlewareInterface
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(protected SessionStorageInterface $session)
|
||||||
protected SessionStorageInterface $session,
|
{
|
||||||
protected array $paths = [],
|
|
||||||
protected ?string $apiPrefix = null
|
|
||||||
) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
{
|
{
|
||||||
$requestPath = $request->getAttribute('route-request-path');
|
|
||||||
$isApi = in_array($requestPath, $this->paths)
|
|
||||||
|| ($this->apiPrefix && Str::startsWith($requestPath, $this->apiPrefix));
|
|
||||||
$request = $request->withAttribute('route-api', $isApi);
|
|
||||||
|
|
||||||
$return = $handler->handle($request);
|
$return = $handler->handle($request);
|
||||||
|
|
||||||
$cookies = $request->getCookieParams();
|
$cookies = $request->getCookieParams();
|
||||||
if (
|
if (
|
||||||
$isApi
|
// Is api (accessible) path
|
||||||
|
$request->getAttribute('route-api-accessible')
|
||||||
|
// Uses native PHP session
|
||||||
&& $this->session instanceof NativeSessionStorage
|
&& $this->session instanceof NativeSessionStorage
|
||||||
|
// No session cookie was sent on request
|
||||||
&& !isset($cookies[$this->session->getName()])
|
&& !isset($cookies[$this->session->getName()])
|
||||||
) {
|
) {
|
||||||
$this->destroyNative();
|
$this->destroyNative();
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Engelsystem\Middleware;
|
|
||||||
|
|
||||||
use Engelsystem\Container\ServiceProvider;
|
|
||||||
|
|
||||||
class SessionHandlerServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
public function register(): void
|
|
||||||
{
|
|
||||||
$this->app
|
|
||||||
->when(SessionHandler::class)
|
|
||||||
->needs('$paths')
|
|
||||||
->give(function () {
|
|
||||||
return [
|
|
||||||
'/atom',
|
|
||||||
'/rss',
|
|
||||||
'/health',
|
|
||||||
'/ical',
|
|
||||||
'/metrics',
|
|
||||||
'/shifts-json-export',
|
|
||||||
'/stats',
|
|
||||||
];
|
|
||||||
});
|
|
||||||
$this->app
|
|
||||||
->when(SessionHandler::class)
|
|
||||||
->needs('$apiPrefix')
|
|
||||||
->give('/api');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,7 @@ use Engelsystem\Http\Response;
|
||||||
use Engelsystem\Models\News;
|
use Engelsystem\Models\News;
|
||||||
use League\OpenAPIValidation\PSR7\OperationAddress as OpenApiAddress;
|
use League\OpenAPIValidation\PSR7\OperationAddress as OpenApiAddress;
|
||||||
use League\OpenAPIValidation\PSR7\ResponseValidator as OpenApiResponseValidator;
|
use League\OpenAPIValidation\PSR7\ResponseValidator as OpenApiResponseValidator;
|
||||||
use League\OpenAPIValidation\PSR7\ValidatorBuilder;
|
use League\OpenAPIValidation\PSR7\ValidatorBuilder as OpenApiValidatorBuilder;
|
||||||
|
|
||||||
class ApiControllerTest extends ControllerTest
|
class ApiControllerTest extends ControllerTest
|
||||||
{
|
{
|
||||||
|
@ -106,7 +106,7 @@ class ApiControllerTest extends ControllerTest
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$openApiDefinition = $this->app->get('path.resources.api') . '/openapi.yml';
|
$openApiDefinition = $this->app->get('path.resources.api') . '/openapi.yml';
|
||||||
$this->validator = (new ValidatorBuilder())
|
$this->validator = (new OpenApiValidatorBuilder())
|
||||||
->fromYamlFile($openApiDefinition)
|
->fromYamlFile($openApiDefinition)
|
||||||
->getResponseValidator();
|
->getResponseValidator();
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ class AuthenticatorTest extends ServiceProviderTest
|
||||||
$session = new Session(new MockArraySessionStorage());
|
$session = new Session(new MockArraySessionStorage());
|
||||||
|
|
||||||
$request = $request->withHeader('Authorization', 'Bearer F00Bar');
|
$request = $request->withHeader('Authorization', 'Bearer F00Bar');
|
||||||
$request = $request->withAttribute('route-api', true);
|
$request = $request->withAttribute('route-api-accessible', true);
|
||||||
$this->app->instance('request', $request);
|
$this->app->instance('request', $request);
|
||||||
User::factory()->create(['api_key' => 'F00Bar']);
|
User::factory()->create(['api_key' => 'F00Bar']);
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ class AuthenticatorTest extends ServiceProviderTest
|
||||||
$this->initDatabase();
|
$this->initDatabase();
|
||||||
|
|
||||||
$request = new Request();
|
$request = new Request();
|
||||||
$request = $request->withAttribute('route-api', true);
|
$request = $request->withAttribute('route-api-accessible', true);
|
||||||
$session = new Session(new MockArraySessionStorage());
|
$session = new Session(new MockArraySessionStorage());
|
||||||
$this->app->instance('request', $request);
|
$this->app->instance('request', $request);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Middleware;
|
||||||
|
|
||||||
|
use Engelsystem\Exceptions\Handler;
|
||||||
|
use Engelsystem\Http\Exceptions\HttpNotFound;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Middleware\ApiRouteHandler;
|
||||||
|
use Engelsystem\Models\User\User;
|
||||||
|
use Engelsystem\Test\Unit\TestCase;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
|
||||||
|
class ApiRouteHandlerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function provideIsApi(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['/foo', false],
|
||||||
|
['/lorem/api', false],
|
||||||
|
['/apiDocs', false],
|
||||||
|
['/api', true],
|
||||||
|
['/api/', true],
|
||||||
|
['/api/lorem', true],
|
||||||
|
['/api/v1/testing', true],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideIsApiAccessiblePath(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
...$this->provideIsApi(),
|
||||||
|
['/metrics', true, false],
|
||||||
|
['/metrics/test', false, false],
|
||||||
|
['/health', true, false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Middleware\ApiRouteHandler::process
|
||||||
|
* @covers \Engelsystem\Middleware\ApiRouteHandler::processApi
|
||||||
|
* @covers \Engelsystem\Middleware\ApiRouteHandler::__construct
|
||||||
|
* @dataProvider provideIsApi
|
||||||
|
*/
|
||||||
|
public function testProcessIsApi(string $uri, bool $isApi): void
|
||||||
|
{
|
||||||
|
$request = Request::create($uri);
|
||||||
|
/** @var RequestHandlerInterface|MockObject $handler */
|
||||||
|
$handler = $this->getMockForAbstractClass(RequestHandlerInterface::class);
|
||||||
|
$response = new Response('response content');
|
||||||
|
|
||||||
|
$handler->expects($this->once())
|
||||||
|
->method('handle')
|
||||||
|
->willReturnCallback(function (ServerRequestInterface $request) use ($response, $isApi) {
|
||||||
|
$this->assertEquals($isApi, $request->getAttribute('route-api'));
|
||||||
|
return $response;
|
||||||
|
});
|
||||||
|
|
||||||
|
$middleware = new ApiRouteHandler();
|
||||||
|
$apiResponse = $middleware->process($request, $handler);
|
||||||
|
|
||||||
|
if ($isApi) {
|
||||||
|
$this->assertEquals('application/json', $apiResponse->getHeaderLine('content-type'));
|
||||||
|
$this->assertEquals('{"message":"response content"}', (string) $apiResponse->getBody());
|
||||||
|
$this->assertNotEmpty($apiResponse->getHeaderLine('Etag'));
|
||||||
|
} else {
|
||||||
|
$this->assertEquals($response, $apiResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Middleware\ApiRouteHandler::process
|
||||||
|
* @dataProvider provideIsApiAccessiblePath
|
||||||
|
*/
|
||||||
|
public function testProcessIsApiAccessiblePath(string $uri, bool $isApiAccessible, bool $isOnlyApi = true): void
|
||||||
|
{
|
||||||
|
$request = Request::create($uri);
|
||||||
|
/** @var RequestHandlerInterface|MockObject $handler */
|
||||||
|
$handler = $this->getMockForAbstractClass(RequestHandlerInterface::class);
|
||||||
|
$response = new Response('response content');
|
||||||
|
|
||||||
|
$handler->expects($this->once())
|
||||||
|
->method('handle')
|
||||||
|
->willReturnCallback(function (ServerRequestInterface $request) use ($response, $isApiAccessible) {
|
||||||
|
$this->assertEquals($isApiAccessible, $request->getAttribute('route-api-accessible'));
|
||||||
|
return $response;
|
||||||
|
});
|
||||||
|
|
||||||
|
$middleware = new ApiRouteHandler();
|
||||||
|
$apiResponse = $middleware->process($request, $handler);
|
||||||
|
|
||||||
|
if (!$isOnlyApi) {
|
||||||
|
$this->assertEquals($response, $apiResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Middleware\ApiRouteHandler::processApi
|
||||||
|
*/
|
||||||
|
public function testProcessApiModelNotFoundException(): void
|
||||||
|
{
|
||||||
|
$request = Request::create('/api/test');
|
||||||
|
/** @var RequestHandlerInterface|MockObject $handler */
|
||||||
|
$handler = $this->getMockForAbstractClass(RequestHandlerInterface::class);
|
||||||
|
|
||||||
|
$handler->expects($this->once())
|
||||||
|
->method('handle')
|
||||||
|
->willReturnCallback(function (): void {
|
||||||
|
throw new ModelNotFoundException(User::class);
|
||||||
|
});
|
||||||
|
|
||||||
|
$middleware = new ApiRouteHandler();
|
||||||
|
$response = $middleware->process($request, $handler);
|
||||||
|
|
||||||
|
$this->assertEquals(404, $response->getStatusCode());
|
||||||
|
$this->assertEquals('{"message":"Not Found"}', (string) $response->getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Middleware\ApiRouteHandler::processApi
|
||||||
|
*/
|
||||||
|
public function testProcessApiHttpException(): void
|
||||||
|
{
|
||||||
|
$request = Request::create('/api/test');
|
||||||
|
/** @var RequestHandlerInterface|MockObject $handler */
|
||||||
|
$handler = $this->getMockForAbstractClass(RequestHandlerInterface::class);
|
||||||
|
|
||||||
|
$handler->expects($this->once())
|
||||||
|
->method('handle')
|
||||||
|
->willReturnCallback(function (): void {
|
||||||
|
throw new HttpNotFound();
|
||||||
|
});
|
||||||
|
|
||||||
|
$middleware = new ApiRouteHandler();
|
||||||
|
$response = $middleware->process($request, $handler);
|
||||||
|
|
||||||
|
$this->assertEquals(404, $response->getStatusCode());
|
||||||
|
$this->assertEquals('{"message":"Not Found"}', (string) $response->getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Middleware\ApiRouteHandler::processApi
|
||||||
|
*/
|
||||||
|
public function testProcessGenericException(): void
|
||||||
|
{
|
||||||
|
$e = new Exception();
|
||||||
|
$request = Request::create('/api/test');
|
||||||
|
/** @var RequestHandlerInterface|MockObject $handler */
|
||||||
|
$handler = $this->getMockForAbstractClass(RequestHandlerInterface::class);
|
||||||
|
$errorHandler = $this->createMock(Handler::class);
|
||||||
|
$this->setExpects($errorHandler, 'exceptionHandler', [$e, true], '', $this->once());
|
||||||
|
$this->app->instance('error.handler', $errorHandler);
|
||||||
|
|
||||||
|
$handler->expects($this->once())
|
||||||
|
->method('handle')
|
||||||
|
->willReturnCallback(function () use ($e): void {
|
||||||
|
throw $e;
|
||||||
|
});
|
||||||
|
|
||||||
|
$middleware = new ApiRouteHandler();
|
||||||
|
$response = $middleware->process($request, $handler);
|
||||||
|
|
||||||
|
$this->assertEquals(500, $response->getStatusCode());
|
||||||
|
$this->assertEquals('{"message":"Internal Server Error"}', (string) $response->getBody());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,46 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Engelsystem\Test\Unit\Middleware;
|
|
||||||
|
|
||||||
use Engelsystem\Middleware\SessionHandler;
|
|
||||||
use Engelsystem\Middleware\SessionHandlerServiceProvider;
|
|
||||||
use Engelsystem\Test\Unit\ServiceProviderTest;
|
|
||||||
use Illuminate\Contracts\Container\ContextualBindingBuilder;
|
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
|
||||||
|
|
||||||
class SessionHandlerServiceProviderTest extends ServiceProviderTest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @covers \Engelsystem\Middleware\SessionHandlerServiceProvider::register()
|
|
||||||
*/
|
|
||||||
public function testRegister(): void
|
|
||||||
{
|
|
||||||
/** @var ContextualBindingBuilder|MockObject $bindingBuilder */
|
|
||||||
$bindingBuilder = $this->createMock(ContextualBindingBuilder::class);
|
|
||||||
$app = $this->getApp(['when']);
|
|
||||||
|
|
||||||
$app->expects($this->once())
|
|
||||||
->method('when')
|
|
||||||
->with(SessionHandler::class)
|
|
||||||
->willReturn($bindingBuilder);
|
|
||||||
|
|
||||||
$bindingBuilder->expects($this->once())
|
|
||||||
->method('needs')
|
|
||||||
->with('$paths')
|
|
||||||
->willReturn($bindingBuilder);
|
|
||||||
|
|
||||||
$bindingBuilder->expects($this->once())
|
|
||||||
->method('give')
|
|
||||||
->willReturnCallback(function (callable $callable): void {
|
|
||||||
$paths = $callable();
|
|
||||||
|
|
||||||
$this->assertIsArray($paths);
|
|
||||||
$this->assertTrue(in_array('/metrics', $paths));
|
|
||||||
});
|
|
||||||
|
|
||||||
$serviceProvider = new SessionHandlerServiceProvider($app);
|
|
||||||
$serviceProvider->register();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -40,13 +40,8 @@ class SessionHandlerTest extends TestCase
|
||||||
|
|
||||||
$request->expects($this->exactly(2))
|
$request->expects($this->exactly(2))
|
||||||
->method('getAttribute')
|
->method('getAttribute')
|
||||||
->with('route-request-path')
|
->with('route-api-accessible')
|
||||||
->willReturnOnConsecutiveCalls('/foo', '/lorem');
|
->willReturnOnConsecutiveCalls(true, false);
|
||||||
|
|
||||||
$request->expects($this->exactly(2))
|
|
||||||
->method('withAttribute')
|
|
||||||
->withConsecutive(['route-api', true], ['route-api', false])
|
|
||||||
->willReturn($request);
|
|
||||||
|
|
||||||
$sessionStorage->expects($this->once())
|
$sessionStorage->expects($this->once())
|
||||||
->method('getName')
|
->method('getName')
|
||||||
|
|
Loading…
Reference in New Issue