Web Host Metadata

RFC6415 defines how web hosts can expose their metadata through resources. Starting with Nextcloud 21, it’s possible to register handlers for HTTP requests to the .well-known/* route.

Writing a handler

A well known handler is a simple class that implements the \OCP\Http\WellKnown\IHandler interface.

  1. <?php
  2. declare(strict_types=1);
  3. namespace OCA\MyApp\Http\WellKnown;
  4. class Handler implements IHandler {
  5. public function handle(string $service, IRequestContext $context, ?IResponse $previousResponse): ?IResponse {
  6. // the handler-specific logic
  7. }
  8. }

The basic concept is that every handler will be called consecutively. A handler can react to the request and return a new response object or modify the one of the previous handler. The first handler will get a $previousResponse of null. The second handler gets whatever the first handler returned, so either null or an instance of \OCP\Http\WellKnown\IResponse.

Example generic handler

  1. <?php
  2. declare(strict_types=1);
  3. namespace OCA\MyApp\Http\WellKnown;
  4. use OCP\AppFramework\Http\JSONResponse;
  5. use OCP\Http\WellKnown\GenericResponse;
  6. use OCP\Http\WellKnown\IHandler;
  7. use OCP\Http\WellKnown\IRequestContext;
  8. use OCP\Http\WellKnown\IResponse;
  9. use OCP\IURLGenerator;
  10. class GenericHandler implements IHandler {
  11. public function handle(string $service, IRequestContext $context, ?IResponse $previousResponse): ?IResponse {
  12. if ($service !== 'nextcloudtest') {
  13. // Not relevant to this handler
  14. return $previousResponse;
  15. }
  16. return new GenericResponse(
  17. new JSONResponse(['message' => 'hello']),
  18. );
  19. }
  20. }

Example webfinger handler

The following example shows how an app could react to RFC6415 webfinger requests:

  1. <?php
  2. declare(strict_types=1);
  3. namespace OCA\MyApp\Http\WellKnown;
  4. use OCP\Http\WellKnown\IHandler;
  5. use OCP\Http\WellKnown\IRequestContext;
  6. use OCP\Http\WellKnown\IResponse;
  7. use OCP\Http\WellKnown\JrdResponse;
  8. use OCP\IURLGenerator;
  9. class WebFingerHandler implements IHandler {
  10. /** @var IURLGenerator */
  11. private $urlGenerator;
  12. public function __construct(IURLGenerator $urlGenerator) {
  13. $this->urlGenerator = $urlGenerator;
  14. }
  15. public function handle(string $service, IRequestContext $context, ?IResponse $previousResponse): ?IResponse {
  16. if ($service !== 'webfinger') {
  17. // Not relevant to this handler
  18. return $previousResponse;
  19. }
  20. $subject = $context->getHttpRequest()->getParam('resource', '');
  21. $href = $this->urlGenerator->linkToRouteAbsolute('myapp.example.test');
  22. // Use the previous response and amend it, if possible
  23. $response = $previousResponse;
  24. if (!($response instanceof JrdResponse)) {
  25. // We override null or any other types
  26. $response = new JrdResponse($subject);
  27. }
  28. return $response->addLink('self', 'application/activity+json', $href);
  29. }
  30. }

Handler registration

The handler class is registered via the bootstrap mechanism of the Application class.

  1. <?php
  2. declare(strict_types=1);
  3. namespace OCA\MyApp\AppInfo;
  4. use OCA\MyApp\Http\WellKnown\Handler;
  5. use OCP\AppFramework\App;
  6. use OCP\AppFramework\Bootstrap\IBootContext;
  7. use OCP\AppFramework\Bootstrap\IBootstrap;
  8. use OCP\AppFramework\Bootstrap\IRegistrationContext;
  9. class Application extends App implements IBootstrap {
  10. public function register(IRegistrationContext $context): void {
  11. $context->registerWellKnownHandler(Handler::class);
  12. }
  13. public function boot(IBootContext $context): void {}
  14. }