@fastify/swagger-ui
Advanced tools
Comparing version 5.1.0 to 5.2.0
'use strict' | ||
function indexHtml (opts) { | ||
const hasLeadingSlash = /^\//.test(opts.prefix) | ||
let routePrefix = opts.prefix | ||
if (opts.indexPrefix) { | ||
routePrefix = `${opts.indexPrefix.replace(/\/$/, '')}/${opts.prefix.replace(/^\//, '')}` | ||
} | ||
return (url) => { | ||
const hasTrailingSlash = /\/$/.test(url) | ||
const prefix = hasTrailingSlash ? `.${opts.staticPrefix}` : `${hasLeadingSlash ? '.' : ''}${opts.prefix}${opts.staticPrefix}` | ||
const prefix = hasTrailingSlash ? `.${opts.staticPrefix}` : `${routePrefix}${opts.staticPrefix}` | ||
return `<!-- HTML for static distribution bundle build --> | ||
@@ -24,3 +27,3 @@ <!DOCTYPE html> | ||
</head> | ||
<body> | ||
@@ -27,0 +30,0 @@ <div id="swagger-ui"></div> |
@@ -18,3 +18,3 @@ 'use strict' | ||
} | ||
const observer = new MutationObserver(mutations => { | ||
@@ -26,3 +26,3 @@ if (document.querySelector(selector)) { | ||
}); | ||
// If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336 | ||
@@ -36,6 +36,6 @@ observer.observe(document.body, { | ||
function resolveUrl(url) { | ||
var currentHref = window.location.href; | ||
let currentHref = window.location.href; | ||
currentHref = currentHref.split('#', 1)[0]; | ||
currentHref = currentHref.endsWith('/') ? currentHref : currentHref + '/'; | ||
var anchor = document.createElement('a'); | ||
const anchor = document.createElement('a'); | ||
anchor.href = currentHref + url; | ||
@@ -42,0 +42,0 @@ return anchor.href |
{ | ||
"name": "@fastify/swagger-ui", | ||
"version": "5.1.0", | ||
"version": "5.2.0", | ||
"description": "Serve Swagger-ui for Fastify", | ||
@@ -59,3 +59,3 @@ "main": "index.js", | ||
"standard": "^17.1.0", | ||
"swagger-ui-dist": "5.17.14", | ||
"swagger-ui-dist": "5.18.2", | ||
"tsd": "^0.31.0" | ||
@@ -62,0 +62,0 @@ }, |
@@ -21,5 +21,11 @@ # @fastify/swagger-ui | ||
| -------------- | --------------- | ---------------------- | | ||
| `^2.0.0` | `^4.0.0` | `^8.0.0` | | ||
| `^1.0.0` | `^4.0.0` | `^8.0.0` | | ||
| `^5.x` | `^5.x` | `^9.x` | | ||
| `^2.x` | `^4.x` | `^8.x` | | ||
| `^1.x` | `^4.x` | `^8.x` | | ||
Please note that if a Fastify version is out of support, then so are the corresponding version(s) of this plugin | ||
in the table above. | ||
See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details. | ||
<a name="usage"></a> | ||
@@ -110,15 +116,16 @@ ## Usage | ||
| Option | Default | Description | | ||
| ------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------- | | ||
| baseDir | undefined | Specify the directory where all spec files that are included in the main one using $ref will be located. By default, this is the directory where the main spec file is located. Provided value should be an absolute path without trailing slash. | | ||
| initOAuth | {} | Configuration options for [Swagger UI initOAuth](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). | | ||
| routePrefix | '/documentation' | Overwrite the default Swagger UI route prefix. | | ||
| staticCSP | false | Enable CSP header for static resources. | | ||
| transformStaticCSP | undefined | Synchronous function to transform CSP header for static resources if the header has been previously set. | | ||
| transformSpecification | undefined | Synchronous function to transform the swagger document. | | ||
| transformSpecificationClone| true | Provide a deepcloned swaggerObject to transformSpecification | | ||
| uiConfig | {} | Configuration options for [Swagger UI](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md). | | ||
| uiHooks | {} | Additional hooks for the documentation's routes. You can provide the `onRequest` and `preHandler` hooks with the same [route's options](https://fastify.dev/docs/latest/Reference/Routes/#routes-options) interface.| | ||
| theme | {} | Add custom JavaScript and CSS to the Swagger UI web page | | ||
| logLevel | info | Allow to define route log level. | | ||
| Option | Default | Description | | ||
| ------------------ | --------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| baseDir | undefined | Specify the directory where all spec files that are included in the main one using $ref will be located. By default, this is the directory where the main spec file is located. Provided value should be an absolute path without trailing slash. | | ||
| initOAuth | {} | Configuration options for [Swagger UI initOAuth](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). | | ||
| routePrefix | '/documentation' | Overwrite the default Swagger UI route prefix. | | ||
| indexPrefix | '' | Add an additional prefix. This is for when the Fastify server is behind path based routing. ex. NGINX | | ||
| staticCSP | false | Enable CSP header for static resources. | | ||
| transformStaticCSP | undefined | Synchronous function to transform CSP header for static resources if the header has been previously set. | | ||
| transformSpecification | undefined | Synchronous function to transform the swagger document. | | ||
| transformSpecificationClone| true | Provide a deepcloned swaggerObject to transformSpecification | | ||
| uiConfig | {} | Configuration options for [Swagger UI](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md). | | ||
| uiHooks | {} | Additional hooks for the documentation's routes. You can provide the `onRequest` and `preHandler` hooks with the same [route's options](https://fastify.dev/docs/latest/Reference/Routes/#routes-options) interface. | | ||
| theme | {} | Add custom JavaScript and CSS to the Swagger UI web page | | ||
| logLevel | info | Allow to define route log level. | | ||
@@ -125,0 +132,0 @@ The plugin will expose the documentation with the following APIs: |
@@ -21,3 +21,3 @@ 'use strict' | ||
t.assert.deepStrictEqual(includesSourceMap, false) | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'application/javascript; charset=UTF-8') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'application/javascript; charset=utf-8') | ||
}) | ||
@@ -38,3 +38,3 @@ | ||
t.assert.deepStrictEqual(includesSourceMap, false) | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/css; charset=UTF-8') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/css; charset=utf-8') | ||
}) |
'use strict' | ||
const t = require('node:test') | ||
const test = t.test | ||
const nodeTest = require('node:test') | ||
const test = nodeTest.test | ||
const Fastify = require('fastify') | ||
@@ -19,2 +19,3 @@ const Swagger = require('@apidevtools/swagger-parser') | ||
const resolve = require('node:path').resolve | ||
const join = require('node:path').join | ||
const readFileSync = require('node:fs').readFileSync | ||
@@ -298,3 +299,3 @@ | ||
t.assert.deepStrictEqual(typeof res.payload, 'string') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/html; charset=UTF-8') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/html; charset=utf-8') | ||
t.assert.deepStrictEqual( | ||
@@ -326,3 +327,3 @@ readFileSync( | ||
t.assert.deepStrictEqual(typeof res.payload, 'string') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/html; charset=UTF-8') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/html; charset=utf-8') | ||
t.assert.deepStrictEqual( | ||
@@ -343,3 +344,3 @@ readFileSync( | ||
t.assert.deepStrictEqual(typeof res.payload, 'string') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/css; charset=UTF-8') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'text/css; charset=utf-8') | ||
t.assert.deepStrictEqual( | ||
@@ -360,3 +361,3 @@ readFileSync( | ||
t.assert.deepStrictEqual(typeof res.payload, 'string') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'application/javascript; charset=UTF-8') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'application/javascript; charset=utf-8') | ||
t.assert.deepStrictEqual( | ||
@@ -377,3 +378,3 @@ readFileSync( | ||
t.assert.deepStrictEqual(typeof res.payload, 'string') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'application/javascript; charset=UTF-8') | ||
t.assert.deepStrictEqual(res.headers['content-type'], 'application/javascript; charset=utf-8') | ||
t.assert.deepStrictEqual( | ||
@@ -547,4 +548,31 @@ readFileSync( | ||
const assertIndexUrls = (t, indexHtml, prefix) => { | ||
t.assert.deepStrictEqual(indexHtml.includes(`href="${prefix}/static/index.css"`), true) | ||
t.assert.deepStrictEqual(indexHtml.includes(`src="${prefix}/static/theme/theme-js.js"`), true) | ||
t.assert.deepStrictEqual(indexHtml.includes(`href="${prefix}/index.css"`), false) | ||
t.assert.deepStrictEqual(indexHtml.includes(`src="${prefix}/theme/theme-js.js"`), false) | ||
} | ||
const validateIndexUrls = async (t, fastify, indexHtml, prefix = '') => { | ||
const hrefs = indexHtml.matchAll(/href="([^"]*)"/g) | ||
for (const [, path] of hrefs) { | ||
const res = await fastify.inject({ | ||
method: 'GET', | ||
url: join(prefix, path) | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
} | ||
const srcs = indexHtml.matchAll(/src="([^"]*)"/g) | ||
for (const [, path] of srcs) { | ||
const res = await fastify.inject({ | ||
method: 'GET', | ||
url: join(prefix, path) | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
} | ||
} | ||
test('/documentation should display index html with correct asset urls', async (t) => { | ||
t.plan(6) | ||
t.plan(13) | ||
const fastify = Fastify() | ||
@@ -558,18 +586,40 @@ await fastify.register(fastifySwagger, swaggerOption) | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
t.assert.deepStrictEqual(res.payload.includes('href="./documentation/static/index.css"'), true) | ||
t.assert.deepStrictEqual(res.payload.includes('src="./documentation/static/theme/theme-js.js"'), true) | ||
t.assert.deepStrictEqual(res.payload.includes('href="./documentation/index.css"'), false) | ||
t.assert.deepStrictEqual(res.payload.includes('src="./documentation/theme/theme-js.js"'), false) | ||
assertIndexUrls(t, res.payload, '/documentation') | ||
await validateIndexUrls(t, fastify, res.payload) | ||
}) | ||
let cssRes = await fastify.inject({ | ||
method: 'GET', | ||
url: '/documentation/static/index.css' | ||
/** | ||
* This emulates when the server is inside an NGINX application that routes by path | ||
*/ | ||
const testCases = [ | ||
['/swagger-app', undefined], | ||
['/swagger-app/', undefined], | ||
['/swagger-app', 'documentation'] | ||
] | ||
testCases.forEach(([prefix, pluginPrefix]) => { | ||
test(`${prefix} ${pluginPrefix} should display index html with correct asset urls when nested`, async (t) => { | ||
t.plan(13) | ||
const fastify = Fastify() | ||
await fastify.register( | ||
async (childFastify) => { | ||
await childFastify.register(fastifySwagger, swaggerOption) | ||
await childFastify.register(fastifySwaggerUi, { indexPrefix: prefix, routePrefix: pluginPrefix, theme: { js: [{ filename: 'theme-js.js' }] } }) | ||
}, | ||
{ | ||
prefix: '/swagger-app' | ||
} | ||
) | ||
const res = await fastify.inject({ | ||
method: 'GET', | ||
url: '/swagger-app/documentation' | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
assertIndexUrls(t, res.payload, '/swagger-app/documentation') | ||
await validateIndexUrls(t, fastify, res.payload) | ||
}) | ||
t.assert.equal(cssRes.statusCode, 200) | ||
cssRes = await fastify.inject({ | ||
method: 'GET', | ||
url: './documentation/static/index.css' | ||
}) | ||
t.assert.equal(cssRes.statusCode, 200) | ||
}) | ||
@@ -580,34 +630,19 @@ | ||
*/ | ||
test('/documentation should display index html with correct asset urls when nested', async (t) => { | ||
t.plan(5) | ||
test('/api/v1/docs should display index html with correct asset urls', async (t) => { | ||
t.plan(13) | ||
const fastify = Fastify() | ||
await fastify.register( | ||
async () => { | ||
await fastify.register(fastifySwagger, swaggerOption) | ||
await fastify.register(fastifySwaggerUi, { theme: { js: [{ filename: 'theme-js.js' }] } }) | ||
}, | ||
{ | ||
prefix: '/swagger-app' | ||
} | ||
) | ||
await fastify.register(fastifySwagger, swaggerOption) | ||
await fastify.register(fastifySwaggerUi, { prefix: '/api/v1/docs', theme: { js: [{ filename: 'theme-js.js' }] } }) | ||
const res = await fastify.inject({ | ||
method: 'GET', | ||
url: '/swagger-app/documentation' | ||
url: '/api/v1/docs' | ||
}) | ||
t.assert.deepStrictEqual(res.payload.includes('href="./documentation/static/index.css"'), true) | ||
t.assert.deepStrictEqual(res.payload.includes('src="./documentation/static/theme/theme-js.js"'), true) | ||
t.assert.deepStrictEqual(res.payload.includes('href="./documentation/index.css"'), false) | ||
t.assert.deepStrictEqual(res.payload.includes('src="./documentation/theme/theme-js.js"'), false) | ||
const cssRes = await fastify.inject({ | ||
method: 'GET', | ||
url: '/swagger-app/documentation/static/index.css' | ||
}) | ||
t.assert.equal(cssRes.statusCode, 200) | ||
t.assert.equal(res.statusCode, 200) | ||
assertIndexUrls(t, res.payload, '/api/v1/docs') | ||
await validateIndexUrls(t, fastify, res.payload) | ||
}) | ||
test('/documentation/ should display index html with correct asset urls', async (t) => { | ||
t.plan(4) | ||
t.plan(13) | ||
const fastify = Fastify() | ||
@@ -621,11 +656,10 @@ await fastify.register(fastifySwagger, swaggerOption) | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
t.assert.strictEqual(res.payload.includes('href="./static/index.css"'), true) | ||
t.assert.strictEqual(res.payload.includes('src="./static/theme/theme-js.js"'), true) | ||
t.assert.strictEqual(res.payload.includes('href="./index.css"'), false) | ||
t.assert.strictEqual(res.payload.includes('src="./theme/theme-js.js"'), false) | ||
assertIndexUrls(t, res.payload, '.') | ||
await validateIndexUrls(t, fastify, res.payload, '/documentation/') | ||
}) | ||
test('/docs should display index html with correct asset urls when documentation prefix is set', async (t) => { | ||
t.plan(4) | ||
t.plan(13) | ||
const fastify = Fastify() | ||
@@ -639,7 +673,6 @@ await fastify.register(fastifySwagger, swaggerOption) | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
t.assert.strictEqual(res.payload.includes('href="./docs/static/index.css"'), true) | ||
t.assert.strictEqual(res.payload.includes('src="./docs/static/theme/theme-js.js"'), true) | ||
t.assert.strictEqual(res.payload.includes('href="./docs/index.css"'), false) | ||
t.assert.strictEqual(res.payload.includes('src="./docs/theme/theme-js.js"'), false) | ||
assertIndexUrls(t, res.payload, '/docs') | ||
await validateIndexUrls(t, fastify, res.payload) | ||
}) | ||
@@ -682,3 +715,3 @@ | ||
test('/documentation/ should display index html with correct asset urls', async (t) => { | ||
t.plan(4) | ||
t.plan(13) | ||
const fastify = Fastify() | ||
@@ -692,11 +725,11 @@ await fastify.register(fastifySwagger, swaggerOption) | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
t.assert.strictEqual(res.payload.includes('href="./static/index.css"'), true) | ||
t.assert.strictEqual(res.payload.includes('src="./static/theme/theme-js.js"'), true) | ||
t.assert.strictEqual(res.payload.includes('href="./index.css"'), false) | ||
t.assert.strictEqual(res.payload.includes('src="./theme/theme-js.js"'), false) | ||
assertIndexUrls(t, res.payload, '.') | ||
await validateIndexUrls(t, fastify, res.payload, '/documentation') | ||
}) | ||
test('/docs should display index html with correct asset urls when documentation prefix is set', async (t) => { | ||
t.plan(4) | ||
t.plan(13) | ||
const fastify = Fastify() | ||
@@ -710,7 +743,7 @@ await fastify.register(fastifySwagger, swaggerOption) | ||
}) | ||
t.assert.equal(res.statusCode, 200) | ||
t.assert.strictEqual(res.payload.includes('href="./docs/static/index.css"'), true) | ||
t.assert.strictEqual(res.payload.includes('src="./docs/static/theme/theme-js.js"'), true) | ||
t.assert.strictEqual(res.payload.includes('href="./docs/index.css"'), false) | ||
t.assert.strictEqual(res.payload.includes('src="./docs/theme/theme-js.js"'), false) | ||
assertIndexUrls(t, res.payload, '/docs') | ||
await validateIndexUrls(t, fastify, res.payload) | ||
}) | ||
@@ -717,0 +750,0 @@ |
@@ -49,2 +49,6 @@ /// <reference lib="dom" /> | ||
/** | ||
* Add an index prefix. This is for when the Fastify server is behind path based routing. ex. NGINX | ||
*/ | ||
indexPrefix?: string; | ||
/** | ||
* Make it explicit that this plugin overrides the prefix value | ||
@@ -51,0 +55,0 @@ */ |
@@ -32,2 +32,3 @@ import fastify, { FastifyReply, FastifyRequest } from 'fastify'; | ||
routePrefix: '/documentation', | ||
indexPrefix: '/custom-prefix' | ||
}); | ||
@@ -37,2 +38,3 @@ | ||
routePrefix: '/documentation', | ||
indexPrefix: '/custom-prefix' | ||
} | ||
@@ -96,2 +98,3 @@ app.register(fastifySwaggerUi, fastifySwaggerOptions); | ||
routePrefix: '/documentation', | ||
indexPrefix: '/custom-prefix' | ||
}) | ||
@@ -98,0 +101,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8827
384
2555674