diff --git a/jsonapi.permissions.yml b/jsonapi.permissions.yml new file mode 100644 index 0000000..f5e5908 --- /dev/null +++ b/jsonapi.permissions.yml @@ -0,0 +1,3 @@ +access jsonapi resource list: + description: 'Gives access to the list of resources served by the JSON API module.' + title: 'Access JSON API resource list' diff --git a/jsonapi.routing.yml b/jsonapi.routing.yml index 9a9ab7d..b2441d2 100644 --- a/jsonapi.routing.yml +++ b/jsonapi.routing.yml @@ -1,2 +1,11 @@ route_callbacks: - - '\Drupal\jsonapi\Routing\Routes::routes' \ No newline at end of file + - '\Drupal\jsonapi\Routing\Routes::routes' + +jsonapi.resource_list: + path: '/jsonapi' + defaults: + _controller: 'Drupal\jsonapi\Controller\EntryPoint::index' + methods: [GET] + requirements: + _permission: 'access jsonapi resource list' + _format: 'api_json' diff --git a/src/Controller/EntryPoint.php b/src/Controller/EntryPoint.php new file mode 100644 index 0000000..9233ef4 --- /dev/null +++ b/src/Controller/EntryPoint.php @@ -0,0 +1,97 @@ +resourceTypeRepository = $resource_type_repository; + $this->renderer = $renderer; + $this->response = $response; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('jsonapi.resource_type.repository'), + $container->get('renderer'), + new CacheableJsonResponse() + ); + } + + /** + * Controller to list all the resources. + */ + public function index() { + // Execute the request in context so the cacheable metadata from the entity + // grants system is caught and added to the response. This is surfaced when + // executing the underlying entity query. + $context = new RenderContext(); + /** @var \Drupal\Core\Cache\CacheableResponseInterface $response */ + $do_build_urls = function () { + $self = Url::fromRoute('jsonapi.resource_list') + ->setOption('absolute', TRUE) + ->setOption('query', ['_format' => 'api_json']); + + return array_reduce($this->resourceTypeRepository->all(), function (array $carry, ResourceType $resource_type) { + // TODO: Learn how to invalidate the cache for this page when a new entity + // type or bundle gets added, removed or updated. + // $this->response->addCacheableDependency($definition); + $url = Url::fromRoute(sprintf('jsonapi.%s.collection', $resource_type->getTypeName())); + $url->setOption('absolute', TRUE); + $url->setOption('query', ['_format' => 'api_json']); + $carry[$resource_type->getTypeName()] = $url->toString(); + + return $carry; + }, ['self' => $self->toString()]); + }; + $urls = $this->renderer->executeInRenderContext($context, $do_build_urls); + if (!$context->isEmpty()) { + $this->response->addCacheableDependency($context->pop()); + } + + $this->response->setData( + [ + 'data' => [], + 'links' => $urls + ] + ); + return $this->response; + } + +} diff --git a/tests/src/Kernel/Controller/EntryPointTest.php b/tests/src/Kernel/Controller/EntryPointTest.php new file mode 100644 index 0000000..e538ad1 --- /dev/null +++ b/tests/src/Kernel/Controller/EntryPointTest.php @@ -0,0 +1,47 @@ +index(); + $this->assertEquals( + ['url.site'], + $processed_response->getCacheableMetadata()->getCacheContexts() + ); + $data = json_decode($processed_response->getContent(), TRUE); + $links = $data['links']; + $this->assertRegExp('/.*\/jsonapi/', $links['self']); + $this->assertRegExp('/.*\/jsonapi\/user\/user/', $links['user--user']); + $this->assertRegExp('/.*\/jsonapi\/node_type\/node_type/', $links['node_type--node_type']); + } + +}