Skip to content

Commit

Permalink
Update Membrane to 0.6
Browse files Browse the repository at this point in the history
  • Loading branch information
charjr committed Sep 26, 2023
1 parent 70aa186 commit abd2bd2
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 34 deletions.
7 changes: 6 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"illuminate/http": "^9.0 || ^10.0",
"illuminate/support": "^9.0 || ^10.0",
"nyholm/psr7": "^1.8",
"membrane/membrane": "^0.3.0",
"membrane/membrane": "^0.6.0",
"symfony/psr-http-message-bridge": "^2.1"
},
"require-dev": {
Expand All @@ -28,5 +28,10 @@
"Membrane\\Laravel\\ServiceProvider"
]
}
},
"config": {
"allow-plugins": {
"infection/extension-installer": true
}
}
}
9 changes: 5 additions & 4 deletions src/ApiProblemBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Crell\ApiProblem\ApiProblem;
use Crell\ApiProblem\HttpConverter;
use Membrane\OpenAPI\Exception\CannotProcessRequest;
use Membrane\OpenAPI\Exception\CannotProcessSpecification;
use Membrane\Renderer\Renderer;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
Expand Down Expand Up @@ -39,12 +40,12 @@ public function buildFromRenderer(Renderer $renderer): SymfonyResponse
return $this->convertToResponse($problem);
}

public function buildFromException(CannotProcessRequest $exception): SymfonyResponse
public function buildFromException(CannotProcessSpecification $exception): SymfonyResponse
{
$errorCode = match ($exception->getCode()) {
0 => 404,
1 => 405,
2 => 406,
CannotProcessSpecification::PATH_NOT_FOUND => 404,
CannotProcessSpecification::METHOD_NOT_FOUND => 405,
// 2 => 406,
default => $this->errorCode
};

Expand Down
6 changes: 3 additions & 3 deletions src/Middleware/RequestValidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Membrane\Laravel\ToPsr7;
use Membrane\Membrane;
use Membrane\OpenAPI\Exception\CannotProcessRequest;
use Membrane\OpenAPI\Exception\CannotProcessSpecification;
use Membrane\OpenAPI\Specification\Request as MembraneRequestSpec;
use Membrane\Result\Result;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
Expand All @@ -35,12 +36,11 @@ public function handle(Request $request, Closure $next): SymfonyResponse

try {
$specification = MembraneRequestSpec::fromPsr7($this->apiSpecPath, $psr7Request);
} catch (CannotProcessRequest $e) {
$result = $this->membrane->process($psr7Request, $specification);
} catch (CannotProcessSpecification $e) {
return $this->apiProblemBuilder->buildFromException($e);
}

$result = $this->membrane->process($psr7Request, $specification);

$this->container->instance(Result::class, $result);

return $next($request);
Expand Down
33 changes: 17 additions & 16 deletions tests/ApiProblemBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Membrane\Laravel;

use Membrane\OpenAPI\Exception\CannotProcessRequest;
use Membrane\OpenAPI\Exception\CannotProcessSpecification;
use Membrane\Renderer\Renderer;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
Expand Down Expand Up @@ -46,7 +46,7 @@ public static function dataSetsToBuildFromException(): array
{
return [
'path not found, no apiResponseTypes' => [
CannotProcessRequest::pathNotFound('api.json', '/pets'),
CannotProcessSpecification::pathNotFound('api.json', '/pets'),
new SymfonyResponse(
'{"title":"Not Found","type":"about:blank","status":404,"detail":"\/pets does not match any specified paths in api.json"}',
404,
Expand All @@ -55,7 +55,7 @@ public static function dataSetsToBuildFromException(): array
[],
],
'path not found, no applicable apiResponseType' => [
CannotProcessRequest::pathNotFound('api.json', '/pets'),
CannotProcessSpecification::pathNotFound('api.json', '/pets'),
new SymfonyResponse(
'{"title":"Not Found","type":"about:blank","status":404,"detail":"\/pets does not match any specified paths in api.json"}',
404,
Expand All @@ -64,7 +64,7 @@ public static function dataSetsToBuildFromException(): array
[418 => 'I\'m a teapot'],
],
'path not found, applicable apiResponseType' => [
CannotProcessRequest::pathNotFound('api.json', '/pets'),
CannotProcessSpecification::pathNotFound('api.json', '/pets'),
new SymfonyResponse(
'{"title":"Not Found","type":"Path Not Found","status":404,"detail":"\/pets does not match any specified paths in api.json"}',
404,
Expand All @@ -73,30 +73,31 @@ public static function dataSetsToBuildFromException(): array
[404 => 'Path Not Found', 418 => 'I\'m a teapot'],
],
'method not found, applicable apiResponseType' => [
CannotProcessRequest::methodNotFound('get'),
CannotProcessSpecification::methodNotFound('get'),
new SymfonyResponse(
'{"title":"Method Not Allowed","type":"Method Not Found","status":405,"detail":"get operation not specified on path"}',
405,
['Content-Type' => 'application/problem+json']
),
[404 => 'Path Not Found', 405 => 'Method Not Found', 418 => 'I\'m a teapot'],
],
'content type not supported, applicable apiResponseType' => [
CannotProcessRequest::unsupportedContent(),
new SymfonyResponse(
'{"title":"Not Acceptable","type":"Not Accepted","status":406,"detail":"APISpec expects application\/json content"}',
406,
['Content-Type' => 'application/problem+json']
),
[404 => 'Path Not Found', 405 => 'Method Not Found', 406 => 'Not Accepted', 418 => 'I\'m a teapot'],
],
//TODO where are content types checked for requests?
// 'content type not supported, applicable apiResponseType' => [
// CannotProcessSpecification::unsupportedContent(),
// new SymfonyResponse(
// '{"title":"Not Acceptable","type":"Not Accepted","status":406,"detail":"APISpec expects application\/json content"}',
// 406,
// ['Content-Type' => 'application/problem+json']
// ),
// [404 => 'Path Not Found', 405 => 'Method Not Found', 406 => 'Not Accepted', 418 => 'I\'m a teapot'],
// ],
];
}

#[Test]
#[DataProvider('dataSetsToBuildFromException')]
public function buildFromExceptionTest(
CannotProcessRequest $exception,
CannotProcessSpecification $exception,
SymfonyResponse $expected,
array $apiResponseTypes
): void {
Expand Down
19 changes: 12 additions & 7 deletions tests/Middleware/RequestValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Membrane\Laravel\ApiProblemBuilder;
use Membrane\Laravel\ToPsr7;
use Membrane\Laravel\ToSymfony;
use Membrane\OpenAPI\Exception\CannotProcessRequest;
use Membrane\OpenAPI\Exception\CannotProcessSpecification;
use Membrane\OpenAPI\Method;
use Membrane\Result\Result;
use PHPUnit\Framework\Attributes\CoversClass;
Expand All @@ -36,8 +36,10 @@ public function registersResultInstanceInContainer(): void
'header' => [],
'cookie' => [],
'body' => '',
'request' => ['method' => 'get', 'operationId' => 'findPets'],
]
);

$apiProblemBuilder = self::createStub(ApiProblemBuilder::class);
$container = self::createMock(Container::class);
$sut = new RequestValidation(__DIR__ . '/../fixtures/petstore-expanded.json', $apiProblemBuilder, $container);
Expand All @@ -49,28 +51,31 @@ public function registersResultInstanceInContainer(): void
$sut->handle(Request::create($url), fn($var) => new Response());
}

public static function dataSetsThatThrowCannotProcessRequest(): array
public static function dataSetsThatThrowCannotProcessSpecification(): array
{
return [
'path not found' => [
'/hats',
Method::GET,
CannotProcessRequest::pathNotFound('petstore-expanded.json', '/hats'),
CannotProcessSpecification::pathNotFound('petstore-expanded.json', '/hats'),
],
'method not found' => [
'/pets',
Method::DELETE,
CannotProcessRequest::methodNotFound(Method::DELETE->value),
CannotProcessSpecification::methodNotFound(Method::DELETE->value),
],
// TODO test 406 from unsupported content-types once Membrane is reading content-types from requests
];
}


#[Test]
#[DataProvider('dataSetsThatThrowCannotProcessRequest')]
public function catchesCannotProcessRequest(string $path, Method $method, CannotProcessRequest $expected): void
{
#[DataProvider('dataSetsThatThrowCannotProcessSpecification')]
public function catchesCannotProcessSpecification(
string $path,
Method $method,
CannotProcessSpecification $expected
): void {
$apiProblemBuilder = self::createMock(ApiProblemBuilder::class);
$sut = new RequestValidation(
__DIR__ . '/../fixtures/petstore-expanded.json',
Expand Down
7 changes: 4 additions & 3 deletions tests/Middleware/ResponseJsonNestedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Contracts\Container\Container;
use Illuminate\Http\Request;
use Membrane\Laravel\ApiProblemBuilder;
use Membrane\Laravel\ToSymfony;
use Membrane\Result\FieldName;
use Membrane\Result\Message;
use Membrane\Result\MessageSet;
Expand All @@ -19,9 +20,9 @@
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;


#[CoversClass('\Membrane\Laravel\Middleware\ResponseJsonNested')]
#[UsesClass(' \Membrane\Laravel\ApiProblemBuilder')]
#[UsesClass(' \Membrane\Laravel\ToSymfony')]
#[CoversClass(ResponseJsonNested::class)]
#[UsesClass(ApiProblemBuilder::class)]
#[UsesClass(ToSymfony::class)]
class ResponseJsonNestedTest extends TestCase
{
public static function dataSetsToHandle(): array
Expand Down

0 comments on commit abd2bd2

Please sign in to comment.