Created and registered middleware which replaces short-code from short-url on rest paths

This commit is contained in:
Alejandro Celaya 2018-09-20 20:27:34 +02:00
parent 622edd2ed1
commit 7ab993b764
11 changed files with 109 additions and 27 deletions

View file

@ -1,12 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
use Shlinkio\Shlink\Common\Middleware\LocaleMiddleware; namespace Shlinkio\Shlink;
use Shlinkio\Shlink\Core\Response\NotFoundHandler;
use Shlinkio\Shlink\Rest\Middleware\BodyParserMiddleware;
use Shlinkio\Shlink\Rest\Middleware\CheckAuthenticationMiddleware;
use Shlinkio\Shlink\Rest\Middleware\CrossDomainMiddleware;
use Shlinkio\Shlink\Rest\Middleware\PathVersionMiddleware;
use Zend\Expressive; use Zend\Expressive;
use Zend\Stratigility\Middleware\ErrorHandler; use Zend\Stratigility\Middleware\ErrorHandler;
@ -17,14 +13,15 @@ return [
'middleware' => [ 'middleware' => [
ErrorHandler::class, ErrorHandler::class,
Expressive\Helper\ContentLengthMiddleware::class, Expressive\Helper\ContentLengthMiddleware::class,
LocaleMiddleware::class, Common\Middleware\LocaleMiddleware::class,
], ],
'priority' => 11, 'priority' => 12,
], ],
'pre-routing-rest' => [ 'pre-routing-rest' => [
'path' => '/rest', 'path' => '/rest',
'middleware' => [ 'middleware' => [
PathVersionMiddleware::class, Rest\Middleware\PathVersionMiddleware::class,
Rest\Middleware\ShortUrl\ShortCodePathMiddleware::class,
], ],
'priority' => 11, 'priority' => 11,
], ],
@ -39,10 +36,10 @@ return [
'rest' => [ 'rest' => [
'path' => '/rest', 'path' => '/rest',
'middleware' => [ 'middleware' => [
CrossDomainMiddleware::class, Rest\Middleware\CrossDomainMiddleware::class,
Expressive\Router\Middleware\ImplicitOptionsMiddleware::class, Expressive\Router\Middleware\ImplicitOptionsMiddleware::class,
BodyParserMiddleware::class, Rest\Middleware\BodyParserMiddleware::class,
CheckAuthenticationMiddleware::class, Rest\Middleware\CheckAuthenticationMiddleware::class,
], ],
'priority' => 5, 'priority' => 5,
], ],
@ -50,7 +47,7 @@ return [
'post-routing' => [ 'post-routing' => [
'middleware' => [ 'middleware' => [
Expressive\Router\Middleware\DispatchMiddleware::class, Expressive\Router\Middleware\DispatchMiddleware::class,
NotFoundHandler::class, Core\Response\NotFoundHandler::class,
], ],
'priority' => 1, 'priority' => 1,
], ],

View file

@ -1,12 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace Shlinkio\Shlink\Rest;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\Core\Options\AppOptions; use Shlinkio\Shlink\Core\Options\AppOptions;
use Shlinkio\Shlink\Core\Service; use Shlinkio\Shlink\Core\Service;
use Shlinkio\Shlink\Rest\Action;
use Shlinkio\Shlink\Rest\Authentication\JWTService;
use Shlinkio\Shlink\Rest\Middleware;
use Shlinkio\Shlink\Rest\Service\ApiKeyService; use Shlinkio\Shlink\Rest\Service\ApiKeyService;
use Zend\I18n\Translator\Translator; use Zend\I18n\Translator\Translator;
use Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory; use Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory;
@ -16,7 +15,7 @@ return [
'dependencies' => [ 'dependencies' => [
'factories' => [ 'factories' => [
JWTService::class => ConfigAbstractFactory::class, Authentication\JWTService::class => ConfigAbstractFactory::class,
ApiKeyService::class => ConfigAbstractFactory::class, ApiKeyService::class => ConfigAbstractFactory::class,
Action\AuthenticateAction::class => ConfigAbstractFactory::class, Action\AuthenticateAction::class => ConfigAbstractFactory::class,
@ -38,14 +37,20 @@ return [
Middleware\PathVersionMiddleware::class => InvokableFactory::class, Middleware\PathVersionMiddleware::class => InvokableFactory::class,
Middleware\CheckAuthenticationMiddleware::class => ConfigAbstractFactory::class, Middleware\CheckAuthenticationMiddleware::class => ConfigAbstractFactory::class,
Middleware\ShortUrl\CreateShortUrlContentNegotiationMiddleware::class => InvokableFactory::class, Middleware\ShortUrl\CreateShortUrlContentNegotiationMiddleware::class => InvokableFactory::class,
Middleware\ShortUrl\ShortCodePathMiddleware::class => InvokableFactory::class,
], ],
], ],
ConfigAbstractFactory::class => [ ConfigAbstractFactory::class => [
JWTService::class => [AppOptions::class], Authentication\JWTService::class => [AppOptions::class],
ApiKeyService::class => ['em'], ApiKeyService::class => ['em'],
Action\AuthenticateAction::class => [ApiKeyService::class, JWTService::class, 'translator', 'Logger_Shlink'], Action\AuthenticateAction::class => [
ApiKeyService::class,
Authentication\JWTService::class,
'translator',
'Logger_Shlink',
],
Action\ShortUrl\CreateShortUrlAction::class => [ Action\ShortUrl\CreateShortUrlAction::class => [
Service\UrlShortener::class, Service\UrlShortener::class,
'translator', 'translator',
@ -88,7 +93,7 @@ return [
Action\Tag\UpdateTagAction::class => [Service\Tag\TagService::class, Translator::class, LoggerInterface::class], Action\Tag\UpdateTagAction::class => [Service\Tag\TagService::class, Translator::class, LoggerInterface::class],
Middleware\CheckAuthenticationMiddleware::class => [ Middleware\CheckAuthenticationMiddleware::class => [
JWTService::class, Authentication\JWTService::class,
'translator', 'translator',
'config.auth.routes_whitelist', 'config.auth.routes_whitelist',
'Logger_Shlink', 'Logger_Shlink',

View file

@ -12,7 +12,7 @@ use Zend\Diactoros\Uri;
class CreateShortUrlAction extends AbstractCreateShortUrlAction class CreateShortUrlAction extends AbstractCreateShortUrlAction
{ {
protected const ROUTE_PATH = '/short-codes'; protected const ROUTE_PATH = '/short-urls';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST];
/** /**

View file

@ -16,7 +16,7 @@ use Zend\I18n\Translator\TranslatorInterface;
class DeleteShortUrlAction extends AbstractRestAction class DeleteShortUrlAction extends AbstractRestAction
{ {
protected const ROUTE_PATH = '/short-codes/{shortCode}'; protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
/** /**

View file

@ -17,7 +17,7 @@ use Zend\I18n\Translator\TranslatorInterface;
class EditShortUrlAction extends AbstractRestAction class EditShortUrlAction extends AbstractRestAction
{ {
protected const ROUTE_PATH = '/short-codes/{shortCode}'; protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
/** /**

View file

@ -15,7 +15,7 @@ use Zend\I18n\Translator\TranslatorInterface;
class EditShortUrlTagsAction extends AbstractRestAction class EditShortUrlTagsAction extends AbstractRestAction
{ {
protected const ROUTE_PATH = '/short-codes/{shortCode}/tags'; protected const ROUTE_PATH = '/short-urls/{shortCode}/tags';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
/** /**

View file

@ -18,7 +18,7 @@ class ListShortUrlsAction extends AbstractRestAction
{ {
use PaginatorUtilsTrait; use PaginatorUtilsTrait;
protected const ROUTE_PATH = '/short-codes'; protected const ROUTE_PATH = '/short-urls';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
/** /**

View file

@ -17,7 +17,7 @@ use Zend\I18n\Translator\TranslatorInterface;
class ResolveShortUrlAction extends AbstractRestAction class ResolveShortUrlAction extends AbstractRestAction
{ {
protected const ROUTE_PATH = '/short-codes/{shortCode}'; protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
/** /**

View file

@ -15,7 +15,7 @@ use Zend\I18n\Translator\TranslatorInterface;
class SingleStepCreateShortUrlAction extends AbstractCreateShortUrlAction class SingleStepCreateShortUrlAction extends AbstractCreateShortUrlAction
{ {
protected const ROUTE_PATH = '/short-codes/shorten'; protected const ROUTE_PATH = '/short-urls/shorten';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
/** /**

View file

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Middleware\ShortUrl;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class ShortCodePathMiddleware implements MiddlewareInterface
{
private const OLD_PATH_PREFIX = '/short-codes';
private const NEW_PATH_PREFIX = '/short-urls';
/**
* Process an incoming server request and return a response, optionally delegating
* response creation to a handler.
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$uri = $request->getUri();
$path = $uri->getPath();
// If the path starts with the old prefix, replace it by the new one
return $handler->handle(
$request->withUri($uri->withPath(\str_replace(self::OLD_PATH_PREFIX, self::NEW_PATH_PREFIX, $path)))
);
}
}

View file

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace ShlinkioTest\Shlink\Rest\Middleware\ShortUrl;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Shlinkio\Shlink\Rest\Middleware\ShortUrl\ShortCodePathMiddleware;
use Zend\Diactoros\Response;
use Zend\Diactoros\Uri;
class ShortCodePathMiddlewareTest extends TestCase
{
private $middleware;
private $requestHandler;
public function setUp()
{
$this->middleware = new ShortCodePathMiddleware();
$this->requestHandler = $this->prophesize(RequestHandlerInterface::class);
$this->requestHandler->handle(Argument::type(ServerRequestInterface::class))->willReturn(new Response());
}
/**
* @test
*/
public function properlyReplacesTheOldPathByTheNewOne()
{
$uri = new Uri('/short-codes/foo');
$request = $this->prophesize(ServerRequestInterface::class);
$request->getUri()->willReturn($uri);
$withUri = $request->withUri(Argument::that(function (UriInterface $uri) {
$path = $uri->getPath();
Assert::assertContains('/short-urls', $path);
Assert::assertNotContains('/short-codes', $path);
return $uri;
}))->willReturn($request->reveal());
$this->middleware->process($request->reveal(), $this->requestHandler->reveal());
$withUri->shouldHaveBeenCalledTimes(1);
}
}