src/Routing/Routes.php | 15 ++++++++++++--- tests/src/Functional/JsonApiFunctionalTest.php | 4 ++-- tests/src/Unit/Routing/RoutesTest.php | 13 ++++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/Routing/Routes.php b/src/Routing/Routes.php index aa1854d..aa06463 100644 --- a/src/Routing/Routes.php +++ b/src/Routing/Routes.php @@ -140,11 +140,10 @@ class Routes implements ContainerInjectionInterface { // Collection route like `/jsonapi/node/article`. $collection_route = new Route('/' . $resource_type->getPath()); - $collection_route->setMethods($resource_type->isLocatable() ? ['GET'] : []); + $collection_route->setMethods(['GET']); // Allow anybody access because "view" and "view label" access are checked // in the controller. $collection_route->setRequirement('_access', 'TRUE'); - $routes->add(static::getRouteName($resource_type, 'collection'), $collection_route); if ($resource_type->isMutable()) { $collection_create_route = new Route($collection_route->getPath()); $collection_create_route->setMethods(['POST']); @@ -152,7 +151,17 @@ class Routes implements ContainerInjectionInterface { $create_requirement = sprintf("%s:%s", $resource_type->getEntityTypeId(), $resource_type->getBundle()); $collection_create_route->setRequirement('_entity_create_access', $create_requirement); $collection_create_route->setRequirement('_csrf_request_header_token', 'TRUE'); - $routes->add(static::getRouteName($resource_type, 'collection.post'), $collection_create_route); + } + // The 'collection' route must always exist. So if the resource type is not + // locatable, assign the "create" route definition to it. + if ($resource_type->isLocatable()) { + $routes->add(static::getRouteName($resource_type, 'collection'), $collection_route); + if ($resource_type->isMutable()) { + $routes->add(static::getRouteName($resource_type, 'collection.post'), $collection_create_route); + } + } + if (!$resource_type->isLocatable() && $resource_type->isMutable()) { + $routes->add(static::getRouteName($resource_type, 'collection'), $collection_create_route); } // Individual routes like `/jsonapi/node/article/{uuid}` or diff --git a/tests/src/Functional/JsonApiFunctionalTest.php b/tests/src/Functional/JsonApiFunctionalTest.php index 9d7af18..e81bab8 100644 --- a/tests/src/Functional/JsonApiFunctionalTest.php +++ b/tests/src/Functional/JsonApiFunctionalTest.php @@ -538,9 +538,9 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase { 'headers' => ['Content-Type' => 'application/vnd.api+json'], ]); $created_response = Json::decode($response->getBody()->__toString()); - $this->assertEquals(403, $response->getStatusCode()); + $this->assertEquals(401, $response->getStatusCode()); $this->assertNotEmpty($created_response['errors']); - $this->assertEquals('Forbidden', $created_response['errors'][0]['title']); + $this->assertEquals('Unauthorized', $created_response['errors'][0]['title']); // 2.1 Authorization error with a user without create permissions. $response = $this->request('POST', $collection_url, [ diff --git a/tests/src/Unit/Routing/RoutesTest.php b/tests/src/Unit/Routing/RoutesTest.php index 0ab2666..c31a68d 100644 --- a/tests/src/Unit/Routing/RoutesTest.php +++ b/tests/src/Unit/Routing/RoutesTest.php @@ -66,9 +66,9 @@ class RoutesTest extends UnitTestCase { // Get the route collection and start making assertions. $routes = $this->routes['ok']->routes(); - // Make sure that there are 6 routes for the non-internal resource and 1 for + // Make sure that there are 7 routes for the non-internal resource and 1 for // the entry point. - $this->assertEquals(7, $routes->count()); + $this->assertEquals(8, $routes->count()); $iterator = $routes->getIterator(); // Check the collection route. @@ -77,7 +77,14 @@ class RoutesTest extends UnitTestCase { $this->assertSame('/jsonapi/entity_type_1/bundle_1_1', $route->getPath()); $this->assertSame(['lorem', 'ipsum'], $route->getOption('_auth')); $this->assertSame('entity_type_1--bundle_1_1', $route->getDefault(Routes::RESOURCE_TYPE_KEY)); - $this->assertEquals(['GET', 'POST'], $route->getMethods()); + $this->assertEquals(['GET'], $route->getMethods()); + $this->assertSame(Routes::FRONT_CONTROLLER, $route->getDefault(RouteObjectInterface::CONTROLLER_NAME)); + // Check the collection POST route. + $route = $iterator->offsetGet('jsonapi.entity_type_1--bundle_1_1.collection.post'); + $this->assertSame('/jsonapi/entity_type_1/bundle_1_1', $route->getPath()); + $this->assertSame(['lorem', 'ipsum'], $route->getOption('_auth')); + $this->assertSame('entity_type_1--bundle_1_1', $route->getDefault(Routes::RESOURCE_TYPE_KEY)); + $this->assertEquals(['POST'], $route->getMethods()); $this->assertSame(Routes::FRONT_CONTROLLER, $route->getDefault(RouteObjectInterface::CONTROLLER_NAME)); $this->assertSame('Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel', $route->getDefault('serialization_class')); }