Include Swagger UI
This commit is contained in:
parent
5c6708cddd
commit
b2824251ae
17 changed files with 433 additions and 47 deletions
|
|
@ -4,6 +4,7 @@ import time
|
|||
import atexit
|
||||
import logging
|
||||
import os
|
||||
import pkg_resources
|
||||
|
||||
from flask import Flask, jsonify, send_file
|
||||
|
||||
|
|
@ -59,8 +60,9 @@ else:
|
|||
app, labthing = create_app(
|
||||
__name__,
|
||||
prefix="/api/v2",
|
||||
description="Test LabThing-based API for OpenFlexure Microscope",
|
||||
title=f"OpenFlexure Microscope {api_microscope.name}",
|
||||
description="Test LabThing-based API for OpenFlexure Microscope",
|
||||
version=pkg_resources.get_distribution("openflexure_microscope").version,
|
||||
)
|
||||
|
||||
# Use custom JSON encoder
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ from .spec import view2path
|
|||
|
||||
from .views.extensions import ExtensionList
|
||||
from .views.tasks import TaskList, TaskResource
|
||||
from .views.docs import docs_blueprint, APISpecResource, W3CThingDescriptionResource
|
||||
|
||||
from openflexure_microscope.common.labthings_core.utilities import get_docstring
|
||||
|
||||
|
|
@ -106,11 +107,12 @@ class LabThing(object):
|
|||
# Add root representation
|
||||
self.app.add_url_rule(self._complete_url("/", ""), "rootrep", self.rootrep)
|
||||
# Add thing description
|
||||
self.app.add_url_rule(self._complete_url("/td", ""), "td", self.td)
|
||||
# self.app.add_url_rule(self._complete_url("/td", ""), "td", self.td)
|
||||
# Add swagger spec
|
||||
self.app.add_url_rule(
|
||||
self._complete_url("/swagger", ""), "swagger", self.swagger
|
||||
)
|
||||
# self.app.add_url_rule(
|
||||
# self._complete_url("/swagger", ""), "swagger", self.swagger
|
||||
# )
|
||||
self.app.register_blueprint(docs_blueprint, url_prefix=self.url_prefix)
|
||||
|
||||
# Add extension overview
|
||||
self.add_resource(
|
||||
|
|
@ -270,35 +272,6 @@ class LabThing(object):
|
|||
return endpoint in self.endpoints
|
||||
|
||||
### Description
|
||||
|
||||
def td(self):
|
||||
"""
|
||||
W3C-style Thing Description
|
||||
"""
|
||||
props = {}
|
||||
for key, prop in self.properties.items():
|
||||
props[key] = {}
|
||||
props[key]["title"] = prop.__name__
|
||||
props[key]["description"] = get_docstring(prop)
|
||||
props[key]["links"] = [{"href": self.url_for(prop, _external=True)}]
|
||||
|
||||
actions = {}
|
||||
for key, prop in self.actions.items():
|
||||
actions[key] = {}
|
||||
actions[key]["title"] = prop.__name__
|
||||
actions[key]["description"] = get_docstring(prop)
|
||||
actions[key]["links"] = [{"href": self.url_for(prop, _external=True)}]
|
||||
|
||||
td = {
|
||||
"id": url_for("td", _external=True),
|
||||
"title": self.title,
|
||||
"description": self.description,
|
||||
"properties": props,
|
||||
"actions": actions,
|
||||
}
|
||||
|
||||
return jsonify(td)
|
||||
|
||||
def rootrep(self):
|
||||
"""
|
||||
Root representation
|
||||
|
|
@ -311,14 +284,13 @@ class LabThing(object):
|
|||
"description": self.description,
|
||||
"links": {
|
||||
"thingDescription": {
|
||||
"href": url_for("td", _external=True),
|
||||
"description": get_docstring(self.td),
|
||||
"href": url_for("labthings_docs.w3c_td", _external=True),
|
||||
"description": get_docstring(W3CThingDescriptionResource),
|
||||
"methods": ["GET"],
|
||||
},
|
||||
"swagger": {
|
||||
"href": url_for("swagger", _external=True),
|
||||
"description": get_docstring(self.swagger),
|
||||
"methods": ["GET"],
|
||||
"swaggerUI": {
|
||||
"href": url_for("labthings_docs.swagger_ui", _external=True),
|
||||
**description_from_view(APISpecResource),
|
||||
},
|
||||
"extensions": {
|
||||
"href": self.url_for(ExtensionList, _external=True),
|
||||
|
|
@ -332,9 +304,3 @@ class LabThing(object):
|
|||
}
|
||||
|
||||
return jsonify(rr)
|
||||
|
||||
def swagger(self):
|
||||
"""
|
||||
OpenAPI v3 documentation
|
||||
"""
|
||||
return jsonify(self.spec.to_dict())
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ def create_app(
|
|||
|
||||
# Create a LabThing
|
||||
labthing = LabThing(
|
||||
app, prefix=prefix, title=title, description=description, version=version
|
||||
app, prefix=prefix, title=title, description=description, version=str(version)
|
||||
)
|
||||
|
||||
# Store references to added-in handlers
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
from flask import abort, url_for, jsonify, render_template, Blueprint
|
||||
|
||||
from openflexure_microscope.common.labthings_core.utilities import get_docstring
|
||||
|
||||
from ...resource import Resource
|
||||
from ...find import current_labthing
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class APISpecResource(Resource):
|
||||
"""
|
||||
OpenAPI v3 documentation
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
OpenAPI v3 documentation
|
||||
"""
|
||||
return jsonify(current_labthing().spec.to_dict())
|
||||
|
||||
|
||||
class SwaggerUIResource(Resource):
|
||||
"""
|
||||
Swagger UI documentation
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
return render_template("swagger-ui.html")
|
||||
|
||||
|
||||
class W3CThingDescriptionResource(Resource):
|
||||
"""
|
||||
W3C-style Thing Description
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
props = {}
|
||||
for key, prop in current_labthing().properties.items():
|
||||
props[key] = {}
|
||||
props[key]["title"] = prop.__name__
|
||||
props[key]["description"] = get_docstring(prop)
|
||||
props[key]["links"] = [
|
||||
{"href": current_labthing().url_for(prop, _external=True)}
|
||||
]
|
||||
|
||||
actions = {}
|
||||
for key, prop in current_labthing().actions.items():
|
||||
actions[key] = {}
|
||||
actions[key]["title"] = prop.__name__
|
||||
actions[key]["description"] = get_docstring(prop)
|
||||
actions[key]["links"] = [
|
||||
{"href": current_labthing().url_for(prop, _external=True)}
|
||||
]
|
||||
|
||||
td = {
|
||||
"id": url_for("labthings_docs.w3c_td", _external=True),
|
||||
"title": current_labthing().title,
|
||||
"description": current_labthing().description,
|
||||
"properties": props,
|
||||
"actions": actions,
|
||||
}
|
||||
|
||||
return jsonify(td)
|
||||
|
||||
|
||||
docs_blueprint = Blueprint(
|
||||
"labthings_docs", __name__, static_folder="./static", template_folder="./templates"
|
||||
)
|
||||
|
||||
docs_blueprint.add_url_rule(
|
||||
"/swagger", view_func=APISpecResource.as_view("swagger_json")
|
||||
)
|
||||
docs_blueprint.add_url_rule(
|
||||
"/swagger-ui", view_func=SwaggerUIResource.as_view("swagger_ui")
|
||||
)
|
||||
docs_blueprint.add_url_rule(
|
||||
"/td", view_func=W3CThingDescriptionResource.as_view("w3c_td")
|
||||
)
|
||||
BIN
openflexure_microscope/common/flask_labthings/views/docs/static/favicon-16x16.png
vendored
Normal file
BIN
openflexure_microscope/common/flask_labthings/views/docs/static/favicon-16x16.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 665 B |
BIN
openflexure_microscope/common/flask_labthings/views/docs/static/favicon-32x32.png
vendored
Normal file
BIN
openflexure_microscope/common/flask_labthings/views/docs/static/favicon-32x32.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 628 B |
60
openflexure_microscope/common/flask_labthings/views/docs/static/index.html
vendored
Normal file
60
openflexure_microscope/common/flask_labthings/views/docs/static/index.html
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<!-- HTML for static distribution bundle build -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after
|
||||
{
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="./swagger-ui-bundle.js"> </script>
|
||||
<script src="./swagger-ui-standalone-preset.js"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
})
|
||||
// End Swagger UI call region
|
||||
|
||||
window.ui = ui
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
68
openflexure_microscope/common/flask_labthings/views/docs/static/oauth2-redirect.html
vendored
Normal file
68
openflexure_microscope/common/flask_labthings/views/docs/static/oauth2-redirect.html
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<title>Swagger UI: OAuth2 Redirect</title>
|
||||
<body onload="run()">
|
||||
</body>
|
||||
</html>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1);
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&")
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value)
|
||||
}
|
||||
) : {}
|
||||
|
||||
isValid = qp.state === sentState
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode"||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
</script>
|
||||
134
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui-bundle.js
vendored
Normal file
134
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui-bundle.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui-bundle.js.map
vendored
Normal file
1
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui-bundle.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
22
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui-standalone-preset.js
vendored
Normal file
22
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui-standalone-preset.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.css
vendored
Normal file
4
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.css.map
vendored
Normal file
1
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
9
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.js
vendored
Normal file
9
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.js.map
vendored
Normal file
1
openflexure_microscope/common/flask_labthings/views/docs/static/swagger-ui.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
38
openflexure_microscope/common/flask_labthings/views/docs/templates/swagger-ui.html
vendored
Normal file
38
openflexure_microscope/common/flask_labthings/views/docs/templates/swagger-ui.html
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link rel="icon" type="image/png" href="{{ url_for('labthings_docs.static', filename='favicon-32x32.png') }}"
|
||||
sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="{{ url_for('labthings_docs.static', filename='favicon-16x16.png') }}"
|
||||
sizes="16x16" />
|
||||
<link href="{{ url_for('labthings_docs.static', filename='swagger-ui.css') }}" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body class="swagger-section">
|
||||
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate> </div>
|
||||
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
|
||||
<script src="{{ url_for('labthings_docs.static', filename='swagger-ui-bundle.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ url_for('labthings_docs.static', filename='swagger-ui-standalone-preset.js') }}"
|
||||
type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
var ui = SwaggerUIBundle({
|
||||
url: "{{ url_for('labthings_docs.swagger_json') }}",
|
||||
dom_id: '#swagger-ui-container',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "BaseLayout"
|
||||
})
|
||||
window.ui = ui
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue