api
This commit is contained in:
13
frontend/web/api-doc/docker/configurator/helpers.js
Normal file
13
frontend/web/api-doc/docker/configurator/helpers.js
Normal file
@ -0,0 +1,13 @@
|
||||
module.exports.indent = function indent(str, len, fromLine = 0) {
|
||||
|
||||
return str
|
||||
.split("\n")
|
||||
.map((line, i) => {
|
||||
if (i + 1 >= fromLine) {
|
||||
return `${Array(len + 1).join(" ")}${line}`
|
||||
} else {
|
||||
return line
|
||||
}
|
||||
})
|
||||
.join("\n")
|
||||
}
|
52
frontend/web/api-doc/docker/configurator/index.js
Executable file
52
frontend/web/api-doc/docker/configurator/index.js
Executable file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Replace static code with configured data based on environment-variables.
|
||||
* This code should be called BEFORE the webserver serve the api-documentation.
|
||||
*/
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
|
||||
const translator = require("./translator")
|
||||
const oauthBlockBuilder = require("./oauth")
|
||||
const indent = require("./helpers").indent
|
||||
|
||||
const START_MARKER = "//<editor-fold desc=\"Changeable Configuration Block\">"
|
||||
const END_MARKER = "//</editor-fold>"
|
||||
|
||||
const targetPath = path.normalize(process.cwd() + "/" + process.argv[2])
|
||||
|
||||
const originalHtmlContent = fs.readFileSync(targetPath, "utf8")
|
||||
|
||||
const startMarkerIndex = originalHtmlContent.indexOf(START_MARKER)
|
||||
const endMarkerIndex = originalHtmlContent.indexOf(END_MARKER)
|
||||
|
||||
const beforeStartMarkerContent = originalHtmlContent.slice(0, startMarkerIndex)
|
||||
const afterEndMarkerContent = originalHtmlContent.slice(
|
||||
endMarkerIndex + END_MARKER.length
|
||||
)
|
||||
|
||||
if (startMarkerIndex < 0 || endMarkerIndex < 0) {
|
||||
console.error("ERROR: Swagger UI was unable to inject Docker configuration data!")
|
||||
console.error("! This can happen when you provide custom HTML/JavaScript to Swagger UI.")
|
||||
console.error("! ")
|
||||
console.error(`! In order to solve this, add the "${START_MARKER}"`)
|
||||
console.error(`! and "${END_MARKER}" markers to your JavaScript.`)
|
||||
console.error("! See the repository for an example:")
|
||||
console.error("! https://github.com/swagger-api/swagger-ui/blob/8c946a02e73ef877d73b7635de27924418ba50f3/dist/swagger-initializer.js#L2-L19")
|
||||
console.error("! ")
|
||||
console.error("! If you're seeing this message and aren't using custom HTML,")
|
||||
console.error("! this message may be a bug. Please file an issue:")
|
||||
console.error("! https://github.com/swagger-api/swagger-ui/issues/new/choose")
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
targetPath,
|
||||
`${beforeStartMarkerContent}
|
||||
${START_MARKER}
|
||||
window.ui = SwaggerUIBundle({
|
||||
${indent(translator(process.env, {injectBaseConfig: true}), 8, 2)}
|
||||
})
|
||||
${indent(oauthBlockBuilder(process.env), 6, 2)}
|
||||
${END_MARKER}
|
||||
${afterEndMarkerContent}`
|
||||
)
|
55
frontend/web/api-doc/docker/configurator/oauth.js
Normal file
55
frontend/web/api-doc/docker/configurator/oauth.js
Normal file
@ -0,0 +1,55 @@
|
||||
const translator = require("./translator")
|
||||
const indent = require("./helpers").indent
|
||||
|
||||
const oauthBlockSchema = {
|
||||
OAUTH_CLIENT_ID: {
|
||||
type: "string",
|
||||
name: "clientId"
|
||||
},
|
||||
OAUTH_CLIENT_SECRET: {
|
||||
type: "string",
|
||||
name: "clientSecret",
|
||||
onFound: () => console.warn("Swagger UI warning: don't use `OAUTH_CLIENT_SECRET` in production!")
|
||||
},
|
||||
OAUTH_REALM: {
|
||||
type: "string",
|
||||
name: "realm"
|
||||
},
|
||||
OAUTH_APP_NAME: {
|
||||
type: "string",
|
||||
name: "appName"
|
||||
},
|
||||
OAUTH_SCOPE_SEPARATOR: {
|
||||
type: "string",
|
||||
name: "scopeSeparator"
|
||||
},
|
||||
OAUTH_SCOPES: {
|
||||
type: "string",
|
||||
name: "scopes"
|
||||
},
|
||||
OAUTH_ADDITIONAL_PARAMS: {
|
||||
type: "object",
|
||||
name: "additionalQueryStringParams"
|
||||
},
|
||||
OAUTH_USE_BASIC_AUTH: {
|
||||
type: "boolean",
|
||||
name: "useBasicAuthenticationWithAccessCodeGrant"
|
||||
},
|
||||
OAUTH_USE_PKCE: {
|
||||
type: "boolean",
|
||||
name: "usePkceWithAuthorizationCodeGrant"
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function oauthBlockBuilder(env) {
|
||||
const translatorResult = translator(env, { schema: oauthBlockSchema })
|
||||
|
||||
if(translatorResult) {
|
||||
return (
|
||||
`ui.initOAuth({
|
||||
${indent(translatorResult, 2)}
|
||||
})`)
|
||||
}
|
||||
|
||||
return ``
|
||||
}
|
111
frontend/web/api-doc/docker/configurator/translator.js
Normal file
111
frontend/web/api-doc/docker/configurator/translator.js
Normal file
@ -0,0 +1,111 @@
|
||||
// Converts an object of environment variables into a Swagger UI config object
|
||||
const configSchema = require("./variables")
|
||||
|
||||
const defaultBaseConfig = {
|
||||
url: {
|
||||
value: "https://petstore.swagger.io/v2/swagger.json",
|
||||
schema: {
|
||||
type: "string",
|
||||
base: true
|
||||
}
|
||||
},
|
||||
dom_id: {
|
||||
value: "#swagger-ui",
|
||||
schema: {
|
||||
type: "string",
|
||||
base: true
|
||||
}
|
||||
},
|
||||
deepLinking: {
|
||||
value: "true",
|
||||
schema: {
|
||||
type: "boolean",
|
||||
base: true
|
||||
}
|
||||
},
|
||||
presets: {
|
||||
value: `[\n SwaggerUIBundle.presets.apis,\n SwaggerUIStandalonePreset\n]`,
|
||||
schema: {
|
||||
type: "array",
|
||||
base: true
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
value: `[\n SwaggerUIBundle.plugins.DownloadUrl\n]`,
|
||||
schema: {
|
||||
type: "array",
|
||||
base: true
|
||||
}
|
||||
},
|
||||
layout: {
|
||||
value: "StandaloneLayout",
|
||||
schema: {
|
||||
type: "string",
|
||||
base: true
|
||||
}
|
||||
},
|
||||
queryConfigEnabled: {
|
||||
value: "false",
|
||||
schema: {
|
||||
type: "boolean",
|
||||
base: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function objectToKeyValueString(env, { injectBaseConfig = false, schema = configSchema, baseConfig = defaultBaseConfig } = {}) {
|
||||
let valueStorage = injectBaseConfig ? Object.assign({}, baseConfig) : {}
|
||||
const keys = Object.keys(env)
|
||||
|
||||
// Compute an intermediate representation that holds candidate values and schemas.
|
||||
//
|
||||
// This is useful for deduping between multiple env keys that set the same
|
||||
// config variable.
|
||||
|
||||
keys.forEach(key => {
|
||||
const varSchema = schema[key]
|
||||
const value = env[key]
|
||||
|
||||
if(!varSchema) return
|
||||
|
||||
if(varSchema.onFound) {
|
||||
varSchema.onFound()
|
||||
}
|
||||
|
||||
const storageContents = valueStorage[varSchema.name]
|
||||
|
||||
if(storageContents) {
|
||||
if (varSchema.legacy === true && !storageContents.schema.base) {
|
||||
// If we're looking at a legacy var, it should lose out to any already-set value
|
||||
// except for base values
|
||||
return
|
||||
}
|
||||
delete valueStorage[varSchema.name]
|
||||
}
|
||||
|
||||
valueStorage[varSchema.name] = {
|
||||
value,
|
||||
schema: varSchema
|
||||
}
|
||||
})
|
||||
|
||||
// Compute a key:value string based on valueStorage's contents.
|
||||
|
||||
let result = ""
|
||||
|
||||
Object.keys(valueStorage).forEach(key => {
|
||||
const value = valueStorage[key]
|
||||
|
||||
const escapedName = /[^a-zA-Z0-9]/.test(key) ? `"${key}"` : key
|
||||
|
||||
if (value.schema.type === "string") {
|
||||
result += `${escapedName}: "${value.value}",\n`
|
||||
} else {
|
||||
result += `${escapedName}: ${value.value === "" ? `undefined` : value.value},\n`
|
||||
}
|
||||
})
|
||||
|
||||
return result.trim()
|
||||
}
|
||||
|
||||
module.exports = objectToKeyValueString
|
125
frontend/web/api-doc/docker/configurator/variables.js
Normal file
125
frontend/web/api-doc/docker/configurator/variables.js
Normal file
@ -0,0 +1,125 @@
|
||||
const standardVariables = {
|
||||
CONFIG_URL: {
|
||||
type: "string",
|
||||
name: "configUrl"
|
||||
},
|
||||
DOM_ID: {
|
||||
type: "string",
|
||||
name: "dom_id"
|
||||
},
|
||||
SPEC: {
|
||||
type: "object",
|
||||
name: "spec"
|
||||
},
|
||||
URL: {
|
||||
type: "string",
|
||||
name: "url"
|
||||
},
|
||||
URLS: {
|
||||
type: "array",
|
||||
name: "urls"
|
||||
},
|
||||
URLS_PRIMARY_NAME: {
|
||||
type: "string",
|
||||
name: "urls.primaryName"
|
||||
},
|
||||
QUERY_CONFIG_ENABLED: {
|
||||
type: "boolean",
|
||||
name: "queryConfigEnabled"
|
||||
},
|
||||
LAYOUT: {
|
||||
type: "string",
|
||||
name: "layout"
|
||||
},
|
||||
DEEP_LINKING: {
|
||||
type: "boolean",
|
||||
name: "deepLinking"
|
||||
},
|
||||
DISPLAY_OPERATION_ID: {
|
||||
type: "boolean",
|
||||
name: "displayOperationId"
|
||||
},
|
||||
DEFAULT_MODELS_EXPAND_DEPTH: {
|
||||
type: "number",
|
||||
name: "defaultModelsExpandDepth"
|
||||
},
|
||||
DEFAULT_MODEL_EXPAND_DEPTH: {
|
||||
type: "number",
|
||||
name: "defaultModelExpandDepth"
|
||||
},
|
||||
DEFAULT_MODEL_RENDERING: {
|
||||
type: "string",
|
||||
name: "defaultModelRendering"
|
||||
},
|
||||
DISPLAY_REQUEST_DURATION: {
|
||||
type: "boolean",
|
||||
name: "displayRequestDuration"
|
||||
},
|
||||
DOC_EXPANSION: {
|
||||
type: "string",
|
||||
name: "docExpansion"
|
||||
},
|
||||
FILTER: {
|
||||
type: "string",
|
||||
name: "filter"
|
||||
},
|
||||
MAX_DISPLAYED_TAGS: {
|
||||
type: "number",
|
||||
name: "maxDisplayedTags"
|
||||
},
|
||||
SHOW_EXTENSIONS: {
|
||||
type: "boolean",
|
||||
name: "showExtensions"
|
||||
},
|
||||
SHOW_COMMON_EXTENSIONS: {
|
||||
type: "boolean",
|
||||
name: "showCommonExtensions"
|
||||
},
|
||||
USE_UNSAFE_MARKDOWN: {
|
||||
type: "boolean",
|
||||
name: "useUnsafeMarkdown"
|
||||
},
|
||||
OAUTH2_REDIRECT_URL: {
|
||||
type: "string",
|
||||
name: "oauth2RedirectUrl"
|
||||
},
|
||||
PERSIST_AUTHORIZATION: {
|
||||
type: "boolean",
|
||||
name: "persistAuthorization"
|
||||
},
|
||||
SHOW_MUTATED_REQUEST: {
|
||||
type: "boolean",
|
||||
name: "showMutatedRequest"
|
||||
},
|
||||
SUPPORTED_SUBMIT_METHODS: {
|
||||
type: "array",
|
||||
name: "supportedSubmitMethods"
|
||||
},
|
||||
TRY_IT_OUT_ENABLED: {
|
||||
type: "boolean",
|
||||
name: "tryItOutEnabled"
|
||||
},
|
||||
VALIDATOR_URL: {
|
||||
type: "string",
|
||||
name: "validatorUrl"
|
||||
},
|
||||
WITH_CREDENTIALS: {
|
||||
type: "boolean",
|
||||
name: "withCredentials",
|
||||
}
|
||||
}
|
||||
|
||||
const legacyVariables = {
|
||||
API_URL: {
|
||||
type: "string",
|
||||
name: "url",
|
||||
legacy: true
|
||||
},
|
||||
API_URLS: {
|
||||
type: "array",
|
||||
name: "urls",
|
||||
legacy: true
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Object.assign({}, standardVariables, legacyVariables)
|
14
frontend/web/api-doc/docker/cors.conf
Normal file
14
frontend/web/api-doc/docker/cors.conf
Normal file
@ -0,0 +1,14 @@
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||
#
|
||||
# Custom headers and headers various browsers *should* be OK with but aren't
|
||||
#
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type' always;
|
||||
#
|
||||
# Tell client that this pre-flight info is valid for 20 days
|
||||
#
|
||||
add_header 'Access-Control-Max-Age' $access_control_max_age always;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
return 204;
|
||||
}
|
52
frontend/web/api-doc/docker/docker-entrypoint.d/40-swagger-ui.sh
Executable file
52
frontend/web/api-doc/docker/docker-entrypoint.d/40-swagger-ui.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
BASE_URL=${BASE_URL:-/}
|
||||
NGINX_ROOT=/usr/share/nginx/html
|
||||
INITIALIZER_SCRIPT=$NGINX_ROOT/swagger-initializer.js
|
||||
NGINX_CONF=/etc/nginx/nginx.conf
|
||||
|
||||
node /usr/share/nginx/configurator $INITIALIZER_SCRIPT
|
||||
|
||||
|
||||
if [[ "${BASE_URL}" != "/" ]]; then
|
||||
sed -i "s|location / {|location $BASE_URL {|g" $NGINX_CONF
|
||||
fi
|
||||
|
||||
if [ "$SWAGGER_JSON_URL" ]; then
|
||||
sed -i "s|https://petstore.swagger.io/v2/swagger.json|$SWAGGER_JSON_URL|g" $INITIALIZER_SCRIPT
|
||||
sed -i "s|http://example.com/api|$SWAGGER_JSON_URL|g" $INITIALIZER_SCRIPT
|
||||
fi
|
||||
|
||||
if [[ -f "$SWAGGER_JSON" ]]; then
|
||||
cp -s "$SWAGGER_JSON" "$NGINX_ROOT"
|
||||
REL_PATH="./$(basename $SWAGGER_JSON)"
|
||||
|
||||
if [[ -z "$SWAGGER_ROOT" ]]; then
|
||||
SWAGGER_ROOT="$(dirname $SWAGGER_JSON)"
|
||||
fi
|
||||
|
||||
if [[ "$BASE_URL" != "/" ]]
|
||||
then
|
||||
BASE_URL=$(echo $BASE_URL | sed 's/\/$//')
|
||||
sed -i \
|
||||
"s|#SWAGGER_ROOT|rewrite ^$BASE_URL(/.*)$ \$1 break;\n #SWAGGER_ROOT|" \
|
||||
$NGINX_CONF
|
||||
fi
|
||||
sed -i "s|#SWAGGER_ROOT|root $SWAGGER_ROOT/;|g" $NGINX_CONF
|
||||
|
||||
sed -i "s|https://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INITIALIZER_SCRIPT
|
||||
sed -i "s|http://example.com/api|$REL_PATH|g" $INITIALIZER_SCRIPT
|
||||
fi
|
||||
|
||||
# enable/disable the address and port for IPv6 addresses that nginx listens on
|
||||
if [[ -n "${PORT_IPV6}" ]]; then
|
||||
sed -i "s|8080;|8080;\n listen [::]:${PORT_IPV6};|g" $NGINX_CONF
|
||||
fi
|
||||
|
||||
# replace the PORT that nginx listens on if PORT is supplied
|
||||
if [[ -n "${PORT}" ]]; then
|
||||
sed -i "s|8080|${PORT}|g" $NGINX_CONF
|
||||
fi
|
||||
|
||||
find $NGINX_ROOT -type f -regex ".*\.\(html\|js\|css\)" -exec sh -c "gzip < {} > {}.gz" \;
|
56
frontend/web/api-doc/docker/nginx.conf
Normal file
56
frontend/web/api-doc/docker/nginx.conf
Normal file
@ -0,0 +1,56 @@
|
||||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
types {
|
||||
text/plain yaml;
|
||||
text/plain yml;
|
||||
}
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
gzip on;
|
||||
gzip_static on;
|
||||
gzip_disable "msie6";
|
||||
|
||||
gzip_vary on;
|
||||
gzip_types text/plain text/css application/javascript;
|
||||
|
||||
map $request_method $access_control_max_age {
|
||||
OPTIONS 1728000; # 20 days
|
||||
}
|
||||
server_tokens off; # Hide Nginx version
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
index index.html index.htm;
|
||||
|
||||
location / {
|
||||
absolute_redirect off;
|
||||
alias /usr/share/nginx/html/;
|
||||
expires 1d;
|
||||
|
||||
location ~ swagger-initializer.js {
|
||||
expires -1;
|
||||
include cors.conf;
|
||||
}
|
||||
|
||||
location ~* \.(?:json|yml|yaml)$ {
|
||||
#SWAGGER_ROOT
|
||||
expires -1;
|
||||
|
||||
include cors.conf;
|
||||
}
|
||||
|
||||
include cors.conf;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user