Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4062851
ModuleSpecHandler.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
ModuleSpecHandler.php
View Options
<?php
namespace
MediaWiki\Rest\Handler
;
use
MediaWiki\Config\Config
;
use
MediaWiki\Config\ServiceOptions
;
use
MediaWiki\MainConfigNames
;
use
MediaWiki\Rest\LocalizedHttpException
;
use
MediaWiki\Rest\Module\Module
;
use
MediaWiki\Rest\RequestData
;
use
MediaWiki\Rest\ResponseFactory
;
use
MediaWiki\Rest\SimpleHandler
;
use
MediaWiki\Rest\Validator\Validator
;
use
Wikimedia\Message\MessageValue
;
use
Wikimedia\ParamValidator\ParamValidator
;
/**
* Core REST API endpoint that outputs an OpenAPI spec of a set of routes.
*/
class
ModuleSpecHandler
extends
SimpleHandler
{
public
const
MODULE_SPEC_PATH
=
'/coredev/v0/specs/module/{module}'
;
/**
* @internal
*/
private
const
CONSTRUCTOR_OPTIONS
=
[
MainConfigNames
::
RightsUrl
,
MainConfigNames
::
RightsText
,
MainConfigNames
::
EmergencyContact
,
MainConfigNames
::
Sitename
,
];
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
run
(
$moduleName
,
$version
=
''
):
array
{
// TODO: implement caching, get cache key from Router.
if
(
$version
!==
''
)
{
$moduleName
.=
'/'
.
$version
;
}
if
(
$moduleName
===
'-'
)
{
// Hack that allows us to fetch a spec for the empty module prefix
$moduleName
=
''
;
}
$module
=
$this
->
getRouter
()->
getModule
(
$moduleName
);
if
(
!
$module
)
{
throw
new
LocalizedHttpException
(
MessageValue
::
new
(
'rest-unknown-module'
)->
params
(
$moduleName
),
404
);
}
return
[
'openapi'
=>
'3.0.0'
,
'info'
=>
$this
->
getInfoSpec
(
$module
),
'servers'
=>
$this
->
getServerSpec
(
$module
),
'paths'
=>
$this
->
getPathsSpec
(
$module
),
'components'
=>
$this
->
getComponentsSpec
(
$module
),
];
}
/**
* @see https://spec.openapis.org/oas/v3.0.0#info-object
*/
private
function
getInfoSpec
(
Module
$module
):
array
{
// TODO: Let Modules provide their name, description, version, etc
$prefix
=
$module
->
getPathPrefix
();
if
(
$prefix
===
''
)
{
$title
=
"Default Module"
;
}
else
{
$title
=
"$prefix Module"
;
}
return
$module
->
getOpenApiInfo
()
+
[
'title'
=>
$title
,
'version'
=>
'undefined'
,
'license'
=>
$this
->
getLicenseSpec
(),
'contact'
=>
$this
->
getContactSpec
(),
];
}
private
function
getLicenseSpec
():
array
{
// 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
{
return
[
'email'
=>
$this
->
options
->
get
(
MainConfigNames
::
EmergencyContact
),
];
}
private
function
getServerSpec
(
Module
$module
):
array
{
$prefix
=
$module
->
getPathPrefix
();
if
(
$prefix
!==
''
)
{
$prefix
=
"/$prefix"
;
}
return
[
[
'url'
=>
$this
->
getRouter
()->
getRouteUrl
(
$prefix
),
]
];
}
private
function
getPathsSpec
(
Module
$module
):
array
{
$specs
=
[];
foreach
(
$module
->
getDefinedPaths
()
as
$path
=>
$methods
)
{
foreach
(
$methods
as
$mth
)
{
$key
=
strtolower
(
$mth
);
$mth
=
strtoupper
(
$mth
);
$specs
[
$path
][
$key
]
=
$this
->
getRouteSpec
(
$module
,
$path
,
$mth
);
}
}
return
$specs
;
}
private
function
getRouteSpec
(
Module
$module
,
string
$path
,
string
$method
):
array
{
$request
=
new
RequestData
(
[
'method'
=>
$method
]
);
$handler
=
$module
->
getHandlerForPath
(
$path
,
$request
,
false
);
$operationSpec
=
$handler
->
getOpenApiSpec
(
$method
);
return
$operationSpec
;
}
private
function
getComponentsSpec
(
Module
$module
)
{
$components
=
[];
// XXX: also collect reusable components from handler specs (but how to avoid name collisions?).
$componentsSources
=
[
[
'schemas'
=>
Validator
::
getParameterTypeSchemas
()
],
ResponseFactory
::
getResponseComponents
()
];
// 2D merge
foreach
(
$componentsSources
as
$cmps
)
{
foreach
(
$cmps
as
$name
=>
$cmp
)
{
$components
[
$name
]
=
array_merge
(
$components
[
$name
]
??
[],
$cmp
);
}
}
return
$components
;
}
public
function
getParamSettings
()
{
return
[
'module'
=>
[
self
::
PARAM_SOURCE
=>
'path'
,
ParamValidator
::
PARAM_TYPE
=>
'string'
,
ParamValidator
::
PARAM_REQUIRED
=>
true
,
],
'version'
=>
[
self
::
PARAM_SOURCE
=>
'path'
,
ParamValidator
::
PARAM_TYPE
=>
'string'
,
ParamValidator
::
PARAM_DEFAULT
=>
''
,
],
];
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 16 2026, 11:32 (12 w, 6 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
91/d4/3a2d4fa30e8977d8daedeaf52f41
Default Alt Text
ModuleSpecHandler.php (4 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment