Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.62% covered (success)
97.62%
41 / 42
88.89% covered (warning)
88.89%
8 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
DiscoveryHandler
97.62% covered (success)
97.62%
41 / 42
88.89% covered (warning)
88.89%
8 / 9
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 getModuleMap
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 getServerList
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getInfoSpec
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 getLicenseSpec
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getContactSpec
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getModuleSpec
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getResponseBodySchemaFileName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Rest\Handler;
4
5use MediaWiki\Config\Config;
6use MediaWiki\Config\ServiceOptions;
7use MediaWiki\MainConfigNames;
8use MediaWiki\Rest\Handler;
9use MediaWiki\Rest\Module\Module;
10
11/**
12 * Core REST API endpoint that outputs discovery information, including a
13 * list of registered modules.
14 * Inspired by Google's API directory, see https://developers.google.com/discovery/v1/reference.
15 */
16class DiscoveryHandler extends Handler {
17    /**
18     * @internal
19     */
20    private const CONSTRUCTOR_OPTIONS = [
21        MainConfigNames::RightsUrl,
22        MainConfigNames::RightsText,
23        MainConfigNames::EmergencyContact,
24        MainConfigNames::Sitename,
25        MainConfigNames::Server,
26    ];
27
28    private ServiceOptions $options;
29
30    public function __construct( Config $config ) {
31        $options = new ServiceOptions( self::CONSTRUCTOR_OPTIONS, $config );
32        $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
33        $this->options = $options;
34    }
35
36    /** @inheritDoc */
37    public function execute() {
38        // NOTE: must match docs/rest/discovery-1.0.json
39        return [
40            'mw-discovery' => '1.0',
41            '$schema' => 'https://www.mediawiki.org/schema/discovery-1.0',
42            'info' => $this->getInfoSpec(),
43            'servers' => $this->getServerList(),
44            'modules' => $this->getModuleMap(),
45            // TODO: link to aggregated spec
46            // TODO: list of component schemas
47        ];
48    }
49
50    private function getModuleMap(): array {
51        $modules = [];
52
53        foreach ( $this->getRouter()->getModuleIds() as $moduleName ) {
54            $module = $this->getRouter()->getModule( $moduleName );
55
56            if ( $module ) {
57                $modules[$moduleName] = $this->getModuleSpec( $moduleName, $module );
58            }
59        }
60
61        return $modules;
62    }
63
64    private function getServerList(): array {
65        // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-object
66        return [
67            [
68                'url' => $this->getRouter()->getRouteUrl( '' ),
69            ]
70        ];
71    }
72
73    private function getInfoSpec(): array {
74        return [
75            'title' => $this->options->get( MainConfigNames::Sitename ),
76            'mediawiki' => MW_VERSION,
77            'license' => $this->getLicenseSpec(),
78            'contact' => $this->getContactSpec(),
79            // TODO: terms of service
80            // TODO: owner/operator
81            // TODO: link to Special:RestSandbox
82            // TODO: link to https://www.mediawiki.org/wiki/API:REST_API
83        ];
84    }
85
86    private function getLicenseSpec(): array {
87        // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#license-object
88        // TODO: get terms-of-use URL, not content license.
89        return [
90            'name' => $this->options->get( MainConfigNames::RightsText ),
91            'url' => $this->options->get( MainConfigNames::RightsUrl ),
92        ];
93    }
94
95    private function getContactSpec(): array {
96        // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#contact-object
97        return [
98            'email' => $this->options->get( MainConfigNames::EmergencyContact ),
99        ];
100    }
101
102    private function getModuleSpec( string $moduleId, Module $module ): array {
103        return $module->getModuleDescription();
104    }
105
106    protected function getResponseBodySchemaFileName( string $method ): ?string {
107        return MW_INSTALL_PATH . '/docs/rest/discovery-1.0.json';
108    }
109}