Socket
Socket
Sign inDemoInstall

@fastify/swagger-ui

Package Overview
Dependencies
Maintainers
17
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fastify/swagger-ui - npm Package Compare versions

Comparing version 1.3.0 to 1.4.0

lib/serialize.js

17

lib/routes.js

@@ -7,2 +7,3 @@ 'use strict'

const rfdc = require('rfdc')()
const swaggerInitializer = require('./swagger-initializer')

@@ -78,14 +79,6 @@ // URI prefix to separate static assets for swagger UI

fastify.route({
url: '/uiConfig',
method: 'GET',
schema: { hide: true },
...hooks,
handler: (req, reply) => {
reply.send(opts.uiConfig)
}
})
const swaggerInitializerContent = swaggerInitializer(opts)
fastify.route({
url: '/initOAuth',
url: `${staticPrefix}/swagger-initializer.js`,
method: 'GET',

@@ -95,3 +88,5 @@ schema: { hide: true },

handler: (req, reply) => {
reply.send(opts.initOAuth)
reply
.header('content-type', 'application/javascript; charset=utf-8')
.send(swaggerInitializerContent)
}

@@ -98,0 +93,0 @@ })

{
"name": "@fastify/swagger-ui",
"version": "1.3.0",
"version": "1.4.0",
"description": "Serve Swagger-ui for Fastify",

@@ -46,3 +46,3 @@ "main": "index.js",

"@apidevtools/swagger-parser": "^10.1.0",
"@fastify/basic-auth": "^4.0.0",
"@fastify/basic-auth": "^5.0.0",
"@fastify/helmet": "^10.0.0",

@@ -54,3 +54,3 @@ "@fastify/pre-commit": "^2.0.2",

"fastify": "^4.0.0",
"fs-extra": "^10.1.0",
"fs-extra": "^11.0.0",
"qs": "^6.11.0",

@@ -60,3 +60,3 @@ "standard": "^17.0.0",

"tap": "^16.3.2",
"tsd": "^0.24.1"
"tsd": "^0.25.0"
},

@@ -63,0 +63,0 @@ "dependencies": {

@@ -111,3 +111,3 @@ # @fastify/swagger-ui

| 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). Must be literal values, see [#5710](https://github.com/swagger-api/swagger-ui/issues/5710). |
| 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://www.fastify.io/docs/latest/Routes/#options) interface.|

@@ -125,2 +125,28 @@ | logLevel | info | Allow to define route log level. |

#### uiConfig
To configure Swagger UI, you need to modify the `uiConfig` option.
It's important to ensure that functions are self-contained. Keep in mind that
you cannot modify the backend code within the `uiConfig` functions, as these
functions are processed only by the browser. You can reference the Swagger UI
element using `ui`, which is assigned to `window.ui`.
##### Example
```js
const fastify = require('fastify')()
await fastify.register(require('@fastify/swagger'))
await fastify.register(require('@fastify/swagger-ui'), {
uiConfig: {
onComplete: function () {
alert('ui has type of ' + typeof ui) // 'ui has type of object'
alert('fastify has type of ' + typeof fastify) // 'fastify has type of undefined'
alert('window has type of ' + typeof window) // 'window has type of object'
alert('global has type of ' + typeof global) // 'global has type of undefined'
}
}
})
```
#### transformSpecification

@@ -127,0 +153,0 @@

@@ -18,3 +18,2 @@ const fs = require('fs')

'oauth2-redirect.html',
'swagger-initializer.js',
'swagger-ui-bundle.js',

@@ -33,51 +32,2 @@ 'swagger-ui-bundle.js.map',

fse.writeFileSync(resolve(`./${folderName}/swagger-initializer.js`), `window.onload = function () {
function resolveUrl (url) {
const anchor = document.createElement('a')
anchor.href = url
return anchor.href
}
function resolveConfig (cb) {
return fetch(
resolveUrl('./uiConfig').replace('${folderName}/uiConfig', 'uiConfig')
)
.then(res => res.json())
.then((config) => {
const resConfig = Object.assign({}, {
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
}, config, {
url: resolveUrl('./json').replace('${folderName}/json', 'json'),
oauth2RedirectUrl: resolveUrl('./oauth2-redirect.html')
});
return cb(resConfig);
})
}
// Begin Swagger UI call region
const buildUi = function (config) {
const ui = SwaggerUIBundle(config)
window.ui = ui
fetch(resolveUrl('./initOAuth').replace('${folderName}/initOAuth', 'initOAuth'))
.then(res => res.json())
.then((config) => {
ui.initOAuth(config);
});
}
// End Swagger UI call region
resolveConfig(buildUi);
}`)
const sha = {

@@ -84,0 +34,0 @@ script: [],

@@ -77,58 +77,2 @@ 'use strict'

test('/documentation/uiConfig route', async (t) => {
t.plan(1)
const fastify = Fastify()
const uiConfig = {
docExpansion: 'full'
}
await fastify.register(fastifySwagger, swaggerOption)
await fastify.register(fastifySwaggerUi, { uiConfig })
fastify.get('/', () => {})
fastify.post('/', () => {})
fastify.get('/example', schemaQuerystring, () => {})
fastify.post('/example', schemaBody, () => {})
fastify.get('/parameters/:id', schemaParams, () => {})
fastify.get('/example1', schemaSecurity, () => {})
const res = await fastify.inject({
method: 'GET',
url: '/documentation/uiConfig'
})
const payload = JSON.parse(res.payload)
t.match(payload, uiConfig, 'uiConfig should be valid')
})
test('/documentation/initOAuth route', async (t) => {
t.plan(1)
const fastify = Fastify()
const initOAuth = {
scopes: ['openid', 'profile', 'email', 'offline_access']
}
await fastify.register(fastifySwagger, swaggerOption)
await fastify.register(fastifySwaggerUi, { initOAuth })
fastify.get('/', () => {})
fastify.post('/', () => {})
fastify.get('/example', schemaQuerystring, () => {})
fastify.post('/example', schemaBody, () => {})
fastify.get('/parameters/:id', schemaParams, () => {})
fastify.get('/example1', schemaSecurity, () => {})
const res = await fastify.inject({
method: 'GET',
url: '/documentation/initOAuth'
})
const payload = JSON.parse(res.payload)
t.match(payload, initOAuth, 'initOAuth should be valid')
})
test('fastify.swagger should return a valid swagger yaml', async (t) => {

@@ -317,3 +261,3 @@ t.plan(3)

test('/documentation/static/:file should send back the correct file', async (t) => {
t.plan(22)
t.plan(21)
const fastify = Fastify()

@@ -365,10 +309,3 @@

t.equal(typeof res.payload, 'string')
t.equal(res.headers['content-type'], 'application/javascript; charset=UTF-8')
t.equal(
readFileSync(
resolve(__dirname, '..', 'static', 'swagger-initializer.js'),
'utf8'
),
res.payload
)
t.equal(res.headers['content-type'], 'application/javascript; charset=utf-8')
t.ok(res.payload.indexOf('resolveUrl') !== -1)

@@ -375,0 +312,0 @@ }

@@ -403,102 +403,1 @@ 'use strict'

})
test('/documentation/uiConfig should have default', async (t) => {
const config = {
mode: 'static',
specification: {
path: './examples/example-static-specification.yaml',
baseDir: resolve(__dirname, '..', '..', 'static')
}
}
t.plan(2)
const fastify = new Fastify()
await fastify.register(fastifySwagger, config)
await fastify.register(fastifySwaggerUi)
const res = await fastify.inject({
method: 'GET',
url: '/documentation/uiConfig'
})
t.equal(res.statusCode, 200)
t.equal(res.payload, '{}')
})
test('/documentation/uiConfig can be customize', async (t) => {
t.plan(2)
const config = {
mode: 'static',
specification: {
path: './examples/example-static-specification.yaml',
baseDir: resolve(__dirname, '..', '..', 'static')
}
}
const fastify = new Fastify()
await fastify.register(fastifySwagger, config)
await fastify.register(fastifySwaggerUi, {
uiConfig: {
docExpansion: 'full'
}
})
const res = await fastify.inject({
method: 'GET',
url: '/documentation/uiConfig'
})
t.equal(res.statusCode, 200)
t.equal(res.payload, '{"docExpansion":"full"}')
})
test('/documentation/initOAuth should have default', async (t) => {
const config = {
mode: 'static',
specification: {
path: './examples/example-static-specification.yaml',
baseDir: resolve(__dirname, '..', '..', 'static')
}
}
t.plan(2)
const fastify = new Fastify()
await fastify.register(fastifySwagger, config)
await fastify.register(fastifySwaggerUi)
const res = await fastify.inject({
method: 'GET',
url: '/documentation/initOAuth'
})
t.equal(res.statusCode, 200)
t.equal(res.payload, '{}')
})
test('/documentation/initOAuth can be customize', async (t) => {
const config = {
mode: 'static',
specification: {
path: './examples/example-static-specification.yaml',
baseDir: resolve(__dirname, '..', '..', 'static')
}
}
t.plan(2)
const fastify = new Fastify()
await fastify.register(fastifySwagger, config)
await fastify.register(fastifySwaggerUi, {
initOAuth: {
scopes: ['openid', 'profile', 'email', 'offline_access']
}
})
const res = await fastify.inject({
method: 'GET',
url: '/documentation/initOAuth'
})
t.equal(res.statusCode, 200)
t.equal(res.payload, '{"scopes":["openid","profile","email","offline_access"]}')
})

@@ -58,38 +58,399 @@ import { FastifyPluginCallback, FastifyReply, FastifyRequest, onRequestHookHandler, preHandlerHookHandler } from 'fastify';

export type FastifySwaggerUiConfigOptions = Partial<{
deepLinking: boolean
displayOperationId: boolean
defaultModelsExpandDepth: number
defaultModelExpandDepth: number
defaultModelRendering: string
displayRequestDuration: boolean
docExpansion: string
filter: boolean | string
layout: string
maxDisplayedTags: number
showExtensions: boolean
showCommonExtensions: boolean
useUnsafeMarkdown: boolean
syntaxHighlight: {
activate?: boolean
theme?: string
} | false
tryItOutEnabled: boolean
validatorUrl: string | null
supportedSubmitMethods: Array<'get' | 'post' | 'put' | 'delete' | 'patch' | 'options'>
persistAuthorization: boolean
}>
type SupportedHTTPMethods = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace";
export type FastifySwaggerInitOAuthOptions = Partial<{
clientId: string,
clientSecret: string,
realm: string,
appName: string,
scopeSeparator: string,
scopes: string | string[],
additionalQueryStringParams: { [key: string]: any },
useBasicAuthenticationWithAccessCodeGrant: boolean,
usePkceWithAuthorizationCodeGrant: boolean
}>
interface PluginsOptions {
/**
* Control behavior of plugins when targeting the same component with wrapComponent.<br/>
* - `legacy` (default) : last plugin takes precedence over the others<br/>
* - `chain` : chain wrapComponents when targeting the same core component,
* allowing multiple plugins to wrap the same component
* @default 'legacy'
*/
pluginLoadType?: PluginLoadType;
}
type PluginLoadType = 'legacy' | 'chain';
type SorterLike =
| "alpha"
| "method"
| {
(name1: string, name2: string): number;
};
interface Request {
[prop: string]: any;
}
interface Response {
[prop: string]: any;
}
/**
* See https://swagger.io/docs/open-source-tools/swagger-ui/customization/plugin-api/
*/
interface SwaggerUIPlugin {
(system: any): {
statePlugins?: {
[stateKey: string]: {
actions?: Indexable | undefined;
reducers?: Indexable | undefined;
selectors?: Indexable | undefined;
wrapActions?: Indexable | undefined;
wrapSelectors?: Indexable | undefined;
};
} | undefined;
components?: Indexable | undefined;
wrapComponents?: Indexable | undefined;
rootInjects?: Indexable | undefined;
afterLoad?: ((system: any) => any) | undefined;
fn?: Indexable | undefined;
};
}
interface Indexable {
[index: string]: any;
}
export type FastifySwaggerUiConfigOptions = {
// Core
/**
* URL to fetch external configuration document from.
*/
configUrl?: string | undefined;
/**
* REQUIRED if domNode is not provided. The ID of a DOM element inside which SwaggerUI will put its user interface.
*/
dom_id?: string | undefined;
/**
* REQUIRED if dom_id is not provided. The HTML DOM element inside which SwaggerUI will put its user interface. Overrides dom_id.
*/
domNode?: HTMLElement | null | undefined;
/**
* A JavaScript object describing the OpenAPI definition. When used, the url parameter will not be parsed. This is useful for testing manually-generated definitions without hosting them
*/
spec?: { [propName: string]: any } | undefined;
/**
* The URL pointing to API definition (normally swagger.json or swagger.yaml). Will be ignored if urls or spec is used.
*/
url?: string | undefined;
/**
* An array of API definition objects ([{url: "<url1>", name: "<name1>"},{url: "<url2>", name: "<name2>"}])
* used by Topbar plugin. When used and Topbar plugin is enabled, the url parameter will not be parsed.
* Names and URLs must be unique among all items in this array, since they're used as identifiers.
*/
urls?: Array<{
url: string;
name: string;
}> | undefined;
// Plugin system
/**
* The name of a component available via the plugin system to use as the top-level layout
* for Swagger UI.
*/
layout?: string | undefined;
/**
* A Javascript object to configure plugin integration and behaviors
*/
pluginsOptions?: PluginsOptions;
/**
* An array of plugin functions to use in Swagger UI.
*/
plugins?: SwaggerUIPlugin[] | undefined;
/**
* An array of presets to use in Swagger UI.
* Usually, you'll want to include ApisPreset if you use this option.
*/
presets?: SwaggerUIPlugin[] | undefined;
// Display
/**
* If set to true, enables deep linking for tags and operations.
* See the Deep Linking documentation for more information.
*/
deepLinking?: boolean | undefined;
/**
* Controls the display of operationId in operations list. The default is false.
*/
displayOperationId?: boolean | undefined;
/**
* The default expansion depth for models (set to -1 completely hide the models).
*/
defaultModelsExpandDepth?: number | undefined;
/**
* The default expansion depth for the model on the model-example section.
*/
defaultModelExpandDepth?: number | undefined;
/**
* Controls how the model is shown when the API is first rendered.
* (The user can always switch the rendering for a given model by clicking the
* 'Model' and 'Example Value' links.)
*/
defaultModelRendering?: "example" | "model" | undefined;
/**
* Controls the display of the request duration (in milliseconds) for "Try it out" requests.
*/
displayRequestDuration?: boolean | undefined;
/**
* Controls the default expansion setting for the operations and tags.
* It can be 'list' (expands only the tags), 'full' (expands the tags and operations)
* or 'none' (expands nothing).
*/
docExpansion?: "list" | "full" | "none" | undefined;
/**
* If set, enables filtering.
* The top bar will show an edit box that you can use to filter the tagged operations that are shown.
* Can be Boolean to enable or disable, or a string, in which case filtering will be enabled
* using that string as the filter expression.
* Filtering is case sensitive matching the filter expression anywhere inside the tag.
*/
filter?: boolean | string | undefined;
/**
* If set, limits the number of tagged operations displayed to at most this many.
* The default is to show all operations.
*/
maxDisplayedTags?: number | undefined;
/**
* Apply a sort to the operation list of each API.
* It can be 'alpha' (sort by paths alphanumerically),
* 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works).
* Default is the order returned by the server unchanged.
*/
operationsSorter?: SorterLike | undefined;
/**
* Controls the display of vendor extension (x-) fields and values for Operations,
* Parameters, Responses, and Schema.
*/
showExtensions?: boolean | undefined;
/**
* Controls the display of extensions (pattern, maxLength, minLength, maximum, minimum) fields
* and values for Parameters.
*/
showCommonExtensions?: boolean | undefined;
/**
* Apply a sort to the tag list of each API.
* It can be 'alpha' (sort by paths alphanumerically)
* or a function (see Array.prototype.sort() to learn how to write a sort function).
* Two tag name strings are passed to the sorter for each pass.
* Default is the order determined by Swagger UI.
*/
tagsSorter?: SorterLike | undefined;
/**
* When enabled, sanitizer will leave style, class and data-* attributes untouched
* on all HTML Elements declared inside markdown strings.
* This parameter is Deprecated and will be removed in 4.0.0.
* @deprecated
*/
useUnsafeMarkdown?: boolean | undefined;
/**
* Provides a mechanism to be notified when Swagger UI has finished rendering a newly provided definition.
*/
onComplete?: (() => any) | undefined;
/**
* Set to false to deactivate syntax highlighting of payloads and cURL command,
* can be otherwise an object with the activate and theme properties.
*/
syntaxHighlight?:
| false
| {
/**
* Whether syntax highlighting should be activated or not.
*/
activate?: boolean | undefined;
/**
* Highlight.js syntax coloring theme to use. (Only these 6 styles are available.)
*/
theme?: "agate" | "arta" | "monokai" | "nord" | "obsidian" | "tomorrow-night" | undefined;
} | undefined;
/**
* Controls whether the "Try it out" section should be enabled by default.
*/
tryItOutEnabled?: boolean | undefined;
/**
* This is the default configuration section for the the requestSnippets plugin.
*/
requestSnippets?: {
generators?: {
[genName: string]: {
title: string;
syntax: string;
};
} | undefined;
defaultExpanded?: boolean | undefined;
/**
* e.g. only show curl bash = ["curl_bash"]
*/
languagesMask?: string[] | undefined;
} | undefined;
// Network
/**
* OAuth redirect URL.
*/
oauth2RedirectUrl?: string | undefined;
/**
* MUST be a function. Function to intercept remote definition,
* "Try it out", and OAuth 2.0 requests.
* Accepts one argument requestInterceptor(request) and must return the modified request,
* or a Promise that resolves to the modified request.
*/
requestInterceptor?: ((a: Request) => Request | Promise<Request>) | undefined;
/**
* MUST be a function. Function to intercept remote definition,
* "Try it out", and OAuth 2.0 responses.
* Accepts one argument responseInterceptor(response) and must return the modified response,
* or a Promise that resolves to the modified response.
*/
responseInterceptor?: ((a: Response) => Response | Promise<Response>) | undefined;
/**
* If set to true, uses the mutated request returned from a requestInterceptor
* to produce the curl command in the UI, otherwise the request
* beforethe requestInterceptor was applied is used.
*/
showMutatedRequest?: boolean | undefined;
/**
* List of HTTP methods that have the "Try it out" feature enabled.
* An empty array disables "Try it out" for all operations.
* This does not filter the operations from the display.
*/
supportedSubmitMethods?: SupportedHTTPMethods[] | undefined;
/**
* By default, Swagger UI attempts to validate specs against swagger.io's online validator.
* You can use this parameter to set a different validator URL,
* for example for locally deployed validators (Validator Badge).
* Setting it to either none, 127.0.0.1 or localhost will disable validation.
*/
validatorUrl?: string | undefined | null;
/**
* If set to true, enables passing credentials, as defined in the Fetch standard,
* in CORS requests that are sent by the browser.
* Note that Swagger UI cannot currently set cookies cross-domain (see swagger-js#1163)
* - as a result, you will have to rely on browser-supplied
* cookies (which this setting enables sending) that Swagger UI cannot control.
*/
withCredentials?: boolean | undefined;
// Macros
/**
* Function to set default values to each property in model.
* Accepts one argument modelPropertyMacro(property), property is immutable
*/
modelPropertyMacro?: ((propName: Readonly<any>) => any) | undefined;
/**
* Function to set default value to parameters.
* Accepts two arguments parameterMacro(operation, parameter).
* Operation and parameter are objects passed for context, both remain immutable
*/
parameterMacro?: ((operation: Readonly<any>, parameter: Readonly<any>) => any) | undefined;
// Authorization
/**
* If set to true, it persists authorization data and it would not be lost on browser close/refresh
*/
persistAuthorization?: boolean | undefined;
}
export type FastifySwaggerInitOAuthOptions = {
/**
* Default clientId.
*/
clientId?: string;
/**
* Never use this parameter in your production environment.
* It exposes crucial security information. This feature is intended for
* dev/test environments only.
* Default clientSecret.
*/
clientSecret?: string,
/**
* realm query parameter (for oauth1) added to authorizationUrl and tokenUrl.
*/
realm?: string;
/**
* application name, displayed in authorization popup.
*/
appName?: string;
/**
* scope separator for passing scopes, encoded before calling, default
* value is a space (encoded value %20).
*
* @default ' '
*/
scopeSeparator?: string;
/**
* string array or scope separator (i.e. space) separated string of
* initially selected oauth scopes
*
* @default []
*/
scopes?: string | string[];
/**
* Additional query parameters added to authorizationUrl and tokenUrl.
* MUST be an object
*/
additionalQueryStringParams?: { [key: string]: any };
/**
* Only activated for the accessCode flow. During the authorization_code
* request to the tokenUrl, pass the Client Password using the HTTP Basic
* Authentication scheme (Authorization header with Basic
* base64encode(client_id + client_secret)).
*
* @default false
*/
useBasicAuthenticationWithAccessCodeGrant?: boolean;
/**
* Only applies to Authorization Code flows. Proof Key for Code Exchange
* brings enhanced security for OAuth public clients.
*
* @default false
*/
usePkceWithAuthorizationCodeGrant?: boolean
}
export type FastifySwaggerUiHooksOptions = Partial<{

@@ -96,0 +457,0 @@ onRequest?: onRequestHookHandler,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc