Permalink
Browse files

Added Swagger spec generation and Swagger UI interface to display API…

… instead of home-grown page
  • Loading branch information...
sergeychernyshev committed Aug 26, 2016
1 parent bea228c commit 062e9cced576c29b32004d1bf7848e42722d1756
View
@@ -37,3 +37,6 @@
[submodule "phptidy"]
path = phptidy
url = https://github.com/cmrcx/phptidy.git
[submodule "swagger-ui"]
path = swagger-ui
url = https://github.com/swagger-api/swagger-ui.git
View
233 api.php
@@ -1,147 +1,100 @@
<?php
require_once(__DIR__ . '/global.php');
if (!array_key_exists('call', $_GET)) {
header('HTTP/1.0 400 Bad Request');
?>
<style>
code {
font-family: monospace,"Courier New";
background-color: #f9f9f9;
padding: 0.2em;
}
dl {
margin-bottom: 2em;
}
if (!array_key_exists('call', $_GET) && array_key_exists('swagger-spec', $_GET)) {
$swagger_spec = array(
'swagger' => '2.0',
'info' => array(
'contact' => array(
'email' => UserConfig::$supportEmailFromEmail
),
'version' => UserConfig::$apiSpecVersion
),
'basePath' => UserConfig::$USERSROOTURL . '/api.php'
);
dt {
margin-bottom: 0.3em;
}
if (UserConfig::$appName) {
$swagger_spec['info']['title'] = UserConfig::$appName;
}
dd {
margin-bottom: 0.5em;
}
if (UserConfig::$termsOfServiceFullURL) {
$swagger_spec['info']['termsOfService'] = UserConfig::$termsOfServiceFullURL;
}
b.call {
color: green;
}
// Swagger tags, e.g. API namespaces
foreach (\StartupAPI\API\Endpoint::getNamespaces() as $namespace) {
$swagger_spec['tags'][] = array(
'name' => $namespace->getSlug(),
'description' => $namespace->getName()
);
}
b.param {
color: blue;
}
</style>
<h1>400 Bad Request</h1>
<p>Required parameter: <b>call</b></p>
<?php
$user = StartupAPI::getUser();
if (!is_null($user) && $user->isAdmin()) {
?>
<p>
Available endpoints:
<?php
$all_endpoints = \StartupAPI\API\Endpoint::getAllEndpointsBySlug();
foreach (\StartupAPI\API\Endpoint::getNamespaces() as $namespace) {
?>
<h2><?php echo $namespace->getName(); ?></h2>
<ul>
<?php
$namespace_slug = $namespace->getSlug();
foreach ($all_endpoints[$namespace_slug] as $endpoint_slug => $endpoints) {
?>
<li>
<h3><?php echo $endpoint_slug ?></h3>
<dl>
<?php
foreach ($endpoints as $method => $endpoint) {
$call = "/$namespace_slug$endpoint_slug";
$params = $endpoint->getParams();
$sample_params_urlencoded = '';
if (count($params) > 0) {
foreach ($params as $name => $param) {
if (!$param->isOptional()) {
$sample_params_urlencoded .= '<b class="param">' . $name . '</b>=';
$sample_params_urlencoded .= urldecode($param->getSampleValue());
}
}
if (!empty($sample_params_urlencoded)) {
$sample_params_urlencoded = '&amp;' . $sample_params_urlencoded;
}
}
?>
<dt>
<code>
<?php echo $method; ?>
<?php
if ($method == 'GET') {
?>
<a href="?call=<?php echo $call . strip_tags($sample_params_urlencoded) ?>"><?php echo UserConfig::$USERSROOTFULLURL ?>/api.php?call=<b class="call"><?php echo $call ?></b><?php echo $sample_params_urlencoded ?></a>
<?php
} else {
echo UserConfig::$USERSROOTFULLURL;
?>/api.php?call=<b class="call"><?php echo $call; ?></b>
<?php
}
?>
</code>
</dt>
<dd>
<?php echo $endpoint->getDescription(); ?>
<?php
if (count($params) > 0) {
?>
<h4>Parameters:</h4>
<dl>
<?php
foreach ($params as $name => $param) {
?>
<dt>
<code><?php echo $name; ?></code>
<?php
if ($param->isOptional()) {
?> (optional)<?php
} else {
?> (required)<?php
}
?>
</dt>
<dd>
<?php
echo $param->getDescription();
if ($param->allowsMultipleValues()) {
?>
(allows multiple values)
<?php
}
?>
</dd>
<?php
}
?>
</dl>
<?php
}
?>
</dd>
<?php
}
?>
</dl>
</li>
<?php
// Swagger paths, e.g. API Endpoints groupped by path
$all_endpoints = \StartupAPI\API\Endpoint::getAllEndpointsBySlug();
foreach ($all_endpoints as $namespace_slug => $namespace_endpoints) {
foreach ($namespace_endpoints as $endpoint_slug => $endpoints) {
foreach ($endpoints as $method => $endpoint) {
$operation = array(
'tags' => array(
$namespace_slug
),
'summary' => $endpoint->getDescription(),
'description' => $endpoint->getDescription(),
'operationId' => get_class($endpoint),
'responses' => array(
'200' => array(
'description' => 'success'
),
'400' => array(
'description' => 'invalid input'
)
)
);
$params = $endpoint->getParams();
foreach ($params as $name => $param) {
$param_spec = array(
'name' => $name,
'description' => $param->getDescription(),
'required' => !$param->isOptional()
);
if ($method === 'GET') {
$param_spec['in'] = 'query';
} else {
$param_spec['in'] = 'formData';
}
if ($param->allowsMultipleValues()) {
$param_spec['type'] = 'array';
$param_spec['collectionFormat'] = 'multi';
}
$operation['parameters'][] = $param_spec;
}
?>
</ul>
<?php
$swagger_spec['paths']["/api.php?call=/$namespace_slug$endpoint_slug"] = array(
strtolower($method) => $operation
);
}
}
?>
</p>
<?php
}
header('Content-type: application/json');
echo json_encode($swagger_spec);
if (json_last_error() !== JSON_ERROR_NONE) {
header('HTTP/1.1 400 Bad Request');
header('Content-type: text/plain');
echo "Error encoding JSON result";
}
exit;
}
if (!array_key_exists('call', $_GET)) {
$template_info = StartupAPI::getTemplateInfo();
StartupAPI::$template->display('@startupapi/swagger-ui.html.twig', $template_info);
exit;
}
@@ -172,7 +125,7 @@
'result' => $endpoint->call($params, $raw_request_body)
);
} catch (\StartupAPI\API\NotFoundException $ex) {
header('HTTP/1.0 404 Not Found');
header('HTTP/1.1 404 Not Found');
$response = array(
'meta' => array(
'success' => false,
@@ -181,7 +134,7 @@
)
);
} catch (\StartupAPI\API\MethodNotAllowedException $ex) {
header('HTTP/1.0 405 Method not allowed');
header('HTTP/1.1 405 Method not allowed');
$response = array(
'meta' => array(
'success' => false,
@@ -190,7 +143,7 @@
)
);
} catch (\StartupAPI\API\UnauthenticatedException $ex) {
header('HTTP/1.0 401 Authentication Required');
header('HTTP/1.1 401 Authentication Required');
header('WWW-Authenticate: FormBased');
$response = array(
'meta' => array(
@@ -200,7 +153,7 @@
)
);
} catch (\StartupAPI\API\UnauthorizedException $ex) {
header('HTTP/1.0 403 Forbidden');
header('HTTP/1.1 403 Forbidden');
$response = array(
'meta' => array(
'success' => false,
@@ -209,7 +162,7 @@
)
);
} catch (\StartupAPI\API\BadParameterException $ex) {
header('HTTP/1.0 400 Bad Parameter');
header('HTTP/1.1 400 Bad Parameter');
$response = array(
'meta' => array(
'success' => false,
@@ -218,7 +171,7 @@
)
);
} catch (\StartupAPI\API\APIException $ex) {
header('HTTP/1.0 500 Server Error');
header('HTTP/1.1 500 Server Error');
$response = array(
'meta' => array(
'success' => false,
View
@@ -888,6 +888,8 @@ class UserConfig {
*/
public static $enable_startupapi_apis = true;
public static $apiSpecVersion = '1.0.0';
/* ========================================================================
*
* Some global functions and default hooks, as well as static initializer
Submodule swagger-ui added at 48e7bc
@@ -4,6 +4,7 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>{% block title %}Users - {{UserConfig.appName}}{% endblock %}</title>
{% include '@startupapi/head_tag.html.twig' %}
{% block head %}{% endblock %}
</head>
<body>
{% include '@startupapi/power_strip.html.twig' %}
@@ -0,0 +1,72 @@
{% extends '@startupapi/page.html.twig' %}
{% block head %}
<link href='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
<link href='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/css/print.css' media='print' rel='stylesheet' type='text/css'/>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/object-assign-pollyfill.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/jquery.wiggle.min.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/handlebars-4.0.5.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/lodash.min.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/backbone-min.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/swagger-ui.min.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/highlight.9.1.0.pack_extended.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/jsoneditor.min.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/marked.js' type='text/javascript'></script>
<script src='{{ UserConfig.USERSROOTURL }}/swagger-ui/dist/lib/swagger-oauth.js' type='text/javascript'></script>
<!-- Some basic translations -->
<!-- <script src='lang/translator.js' type='text/javascript'></script> -->
<!-- <script src='lang/ru.js' type='text/javascript'></script> -->
<!-- <script src='lang/en.js' type='text/javascript'></script> -->
<script type="text/javascript">
$(function () {
hljs.configure({
highlightSizeThreshold: 5000
});
// Pre load translate...
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
window.swaggerUi = new SwaggerUi({
url: '{{ UserConfig.USERSROOTURL }}/api.php?swagger-spec',
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
onComplete: function(swaggerApi, swaggerUi){
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: "list",
jsonEditor: false,
defaultModelRendering: 'schema',
showRequestHeaders: false
});
window.swaggerUi.load();
function log() {
if ('console' in window) {
console.log.apply(console, arguments);
}
}
});
</script>
{% endblock %}
{% block content %}
<div class="container-fluid" style="margin-bottom: 75px">
<div class="swagger-section">
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</div>
</div>
{% endblock %}
@@ -4,6 +4,7 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>{% block title %}Users - {{UserConfig.appName}}{% endblock %}</title>
{% include '@startupapi/head_tag.html.twig' %}
{% block head %}{% endblock %}
</head>
<body>
Oops, something went wrong.

0 comments on commit 062e9cc

Please sign in to comment.