aboutsummaryrefslogtreecommitdiffstats
path: root/includes/Rest/Handler/DiscoveryHandler.php
blob: 0a80c0b61b37ec1b24026adf3be28ce2720d4f93 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?php

namespace MediaWiki\Rest\Handler;

use MediaWiki\Config\Config;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\MainConfigNames;
use MediaWiki\Rest\Handler;
use MediaWiki\Rest\Module\Module;

/**
 * Core REST API endpoint that outputs discovery information, including a
 * list of registered modules.
 * Inspired by Google's API directory, see https://developers.google.com/discovery/v1/reference.
 */
class DiscoveryHandler extends Handler {
	/**
	 * @internal
	 */
	private const CONSTRUCTOR_OPTIONS = [
		MainConfigNames::RightsUrl,
		MainConfigNames::RightsText,
		MainConfigNames::EmergencyContact,
		MainConfigNames::Sitename,
		MainConfigNames::Server,
	];

	private ServiceOptions $options;

	public function __construct( Config $config ) {
		$options = new ServiceOptions( self::CONSTRUCTOR_OPTIONS, $config );
		$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
		$this->options = $options;
	}

	public function execute() {
		// NOTE: must match docs/rest/discovery-1.0.json
		return [
			'mw-discovery' => '1.0',
			'$schema' => 'https://www.mediawiki.org/schema/discovery-1.0',
			'info' => $this->getInfoSpec(),
			'servers' => $this->getServerList(),
			'modules' => $this->getModuleMap(),
			// TODO: link to aggregated spec
			// TODO: list of component schemas
		];
	}

	private function getModuleMap(): array {
		$modules = [];

		foreach ( $this->getRouter()->getModuleIds() as $moduleName ) {
			$module = $this->getRouter()->getModule( $moduleName );

			if ( $module ) {
				$modules[$moduleName] = $this->getModuleSpec( $moduleName, $module );
			}
		}

		return $modules;
	}

	private function getServerList(): array {
		// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-object
		return [
			[
				'url' => $this->getRouter()->getRouteUrl( '' ),
			]
		];
	}

	private function getInfoSpec(): array {
		return [
			'title' => $this->options->get( MainConfigNames::Sitename ),
			'mediawiki' => MW_VERSION,
			'license' => $this->getLicenseSpec(),
			'contact' => $this->getContactSpec(),
			// TODO: terms of service
			// TODO: owner/operator
			// TODO: link to Special:RestSandbox
			// TODO: link to https://www.mediawiki.org/wiki/API:REST_API
		];
	}

	private function getLicenseSpec(): array {
		// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#license-object
		// TODO: get terms-of-use URL, not content license.
		return [
			'name' => $this->options->get( MainConfigNames::RightsText ),
			'url' => $this->options->get( MainConfigNames::RightsUrl ),
		];
	}

	private function getContactSpec(): array {
		// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#contact-object
		return [
			'email' => $this->options->get( MainConfigNames::EmergencyContact ),
		];
	}

	private function getModuleSpec( string $moduleId, Module $module ): array {
		return $module->getModuleDescription();
	}

	protected function getResponseBodySchemaFileName( string $method ): ?string {
		return 'docs/rest/discovery-1.0.json';
	}
}