Skip to content

Commit

Permalink
Merge pull request #2840 from lucas-gregoire/feat/allow-to-disable-sw…
Browse files Browse the repository at this point in the history
…agger-ui

feat: allow to disable Swagger UI
  • Loading branch information
kamilmysliwiec authored Jul 1, 2024
2 parents 91a7c76 + d56087c commit c541886
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 113 deletions.
79 changes: 69 additions & 10 deletions e2e/express.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('Express Swagger', () => {
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
// to showcase that in new implementation u can use custom swagger-ui path. Useful when using e.g. webpack
customSwaggerUiPath: path.resolve(`./node_modules/swagger-ui-dist`),
customSwaggerUiPath: path.resolve(`./node_modules/swagger-ui-dist`)
});

await app.init();
Expand Down Expand Up @@ -114,6 +114,55 @@ describe('Express Swagger', () => {
});
});

describe('disabled Swagger UI but served JSON/YAML definitions', () => {
const SWAGGER_RELATIVE_URL = '/apidoc';

beforeEach(async () => {
const swaggerDocument = SwaggerModule.createDocument(
app,
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
swaggerUiEnabled: false
});

await app.init();
});

afterEach(async () => {
await app.close();
});

it('should serve the JSON definition file', async () => {
const response = await request(app.getHttpServer()).get(
`${SWAGGER_RELATIVE_URL}-json`
);

expect(response.status).toEqual(200);
expect(Object.keys(response.body).length).toBeGreaterThan(0);
});

it('should serve the YAML definition file', async () => {
const response = await request(app.getHttpServer()).get(
`${SWAGGER_RELATIVE_URL}-yaml`
);

expect(response.status).toEqual(200);
expect(response.text.length).toBeGreaterThan(0);
});

it.each([
'/apidoc',
'/apidoc/',
'/apidoc/swagger-ui-bundle.js',
'/apidoc/swagger-ui-init.js'
])('should not serve "%s"', async (file) => {
const response = await request(app.getHttpServer()).get(file);

expect(response.status).toEqual(404);
});
});

describe('custom documents endpoints', () => {
const JSON_CUSTOM_URL = '/apidoc-json';
const YAML_CUSTOM_URL = '/apidoc-yaml';
Expand Down Expand Up @@ -154,10 +203,10 @@ describe('Express Swagger', () => {
`${JSON_CUSTOM_URL}?description=My%20custom%20description`
);

expect(response.body.info.description).toBe("My custom description");
expect(response.body.info.description).toBe('My custom description');
});

it('yaml document should be server in the custom url', async () => {
it('yaml document should be served in the custom url', async () => {
const response = await request(app.getHttpServer()).get(YAML_CUSTOM_URL);

expect(response.status).toEqual(200);
Expand All @@ -168,7 +217,7 @@ describe('Express Swagger', () => {
const response = await request(app.getHttpServer()).get(
`${YAML_CUSTOM_URL}?description=My%20custom%20description`
);
expect(response.text).toContain("My custom description");
expect(response.text).toContain('My custom description');
});
});

Expand Down Expand Up @@ -244,13 +293,17 @@ describe('Express Swagger', () => {
customfavIcon: CUSTOM_FAVICON,
customSiteTitle: CUSTOM_SITE_TITLE,
customCssUrl: CUSTOM_CSS_URL,
patchDocumentOnRequest<ExpressRequest, ExpressResponse> (req, res, document) {
patchDocumentOnRequest<ExpressRequest, ExpressResponse>(
req,
res,
document
) {
return {
...document,
info: {
description: req.query.description
}
}
};
}
});

Expand Down Expand Up @@ -313,23 +366,29 @@ describe('Express Swagger', () => {
);

SwaggerModule.setup('/:customer/', app, swaggerDocument, {
patchDocumentOnRequest<ExpressRequest, ExpressResponse> (req, res, document) {
patchDocumentOnRequest<ExpressRequest, ExpressResponse>(
req,
res,
document
) {
return {
...document,
info: {
description: `${req.params.customer}'s API documentation`
}
}
};
}
});

await app.init();

const response: Response = await request(app.getHttpServer()).get('/customer-1/swagger-ui-init.js');
const response: Response = await request(app.getHttpServer()).get(
'/customer-1/swagger-ui-init.js'
);

await app.close();
expect(response.text).toContain("customer-1's API documentation");
})
});

afterEach(async () => {
await app.close();
Expand Down
96 changes: 90 additions & 6 deletions lib/interfaces/swagger-custom-options.interface.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,107 @@
import { SwaggerUiOptions } from './swagger-ui-options.interface';
import { SwaggerDocumentOptions } from './swagger-document-options.interface';
import { OpenAPIObject } from './open-api-spec.interface';

export interface SwaggerCustomOptions {
/**
* If `true`, Swagger resources paths will be prefixed by the global prefix set through `setGlobalPrefix()`.
* Default: `false`.
* @see https://docs.nestjs.com/faq/global-prefix
*/
useGlobalPrefix?: boolean;

/**
* If `false`, only API definitions (JSON and YAML) will be served (on `/{path}-json` and `/{path}-yaml`).
* This is particularly useful if you are already hosting a Swagger UI somewhere else and just want to serve API definitions.
* Default: `true`.
*/
swaggerUiEnabled?: boolean;

/**
* Url point the API definition to load in Swagger UI.
*/
swaggerUrl?: string;

/**
* Path of the JSON API definition to serve.
* Default: `{{path}}-json`.
*/
jsonDocumentUrl?: string;

/**
* Path of the YAML API definition to serve.
* Default: `{{path}}-json`.
*/
yamlDocumentUrl?: string;

/**
* Hook allowing to alter the OpenAPI document before being served.
* It's called after the document is generated and before it is served as JSON & YAML.
*/
patchDocumentOnRequest?: <TRequest = any, TResponse = any>(
req: TRequest,
res: TResponse,
document: OpenAPIObject
) => OpenAPIObject;

/**
* If `true`, the selector of OpenAPI definitions is displayed in the Swagger UI interface.
* Default: `false`.
*/
explorer?: boolean;

/**
* Additional Swagger UI options
*/
swaggerOptions?: SwaggerUiOptions;

/**
* Custom CSS styles to inject in Swagger UI page.
*/
customCss?: string;

/**
* URL(s) of a custom CSS stylesheet to load in Swagger UI page.
*/
customCssUrl?: string | string[];

/**
* URL(s) of custom JavaScript files to load in Swagger UI page.
*/
customJs?: string | string[];

/**
* Custom JavaScript scripts to load in Swagger UI page.
*/
customJsStr?: string | string[];

/**
* Custom favicon for Swagger UI page.
*/
customfavIcon?: string;
customSwaggerUiPath?: string;
swaggerUrl?: string;

/**
* Custom title for Swagger UI page.
*/
customSiteTitle?: string;

/**
* File system path (ex: ./node_modules/swagger-ui-dist) containing static Swagger UI assets.
*/
customSwaggerUiPath?: string;

/**
* @deprecated This property has no effect.
*/
validatorUrl?: string;

/**
* @deprecated This property has no effect.
*/
url?: string;

/**
* @deprecated This property has no effect.
*/
urls?: Record<'url' | 'name', string>[];
jsonDocumentUrl?: string;
yamlDocumentUrl?: string;
patchDocumentOnRequest?: <TRequest = any, TResponse = any> (req: TRequest, res: TResponse, document: OpenAPIObject) => OpenAPIObject;

}
Loading

0 comments on commit c541886

Please sign in to comment.