Skip to content

Commit

Permalink
feat(swagger): introduce raw option for document serving control
Browse files Browse the repository at this point in the history
  • Loading branch information
mag123c committed Dec 4, 2024
1 parent 9752fcb commit bc6c7ba
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 33 deletions.
129 changes: 127 additions & 2 deletions e2e/express.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ describe('Express Swagger', () => {
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
documentsEnabled: false
raw: false
});

await app.init();
Expand Down Expand Up @@ -217,7 +217,7 @@ describe('Express Swagger', () => {
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
swaggerUiEnabled: false,
documentsEnabled: false
raw: false
});

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

describe('Serve only JSON definition when raw is ["json"]', () => {
const SWAGGER_RELATIVE_URL = '/apidoc';

beforeEach(async () => {
const swaggerDocument = SwaggerModule.createDocument(
app,
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
raw: ['json']
});
await app.init();
});

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

it('should serve only 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 not serve the YAML definition file', async () => {
const response = await request(app.getHttpServer()).get(
`${SWAGGER_RELATIVE_URL}-yaml`
);
expect(response.status).toEqual(404);
});

it.each([SWAGGER_RELATIVE_URL, `${SWAGGER_RELATIVE_URL}/`])(
'should serve Swagger UI at "%s"',
async (url) => {
const response = await request(app.getHttpServer()).get(url);
expect(response.status).toEqual(200);
}
);
});

describe('Serve only YAML definition when raw is ["yaml"]', () => {
const SWAGGER_RELATIVE_URL = '/apidoc';

beforeEach(async () => {
const swaggerDocument = SwaggerModule.createDocument(
app,
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
raw: ['yaml']
});
await app.init();
});

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

it('should serve only 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('should not serve the JSON definition file', async () => {
const response = await request(app.getHttpServer()).get(
`${SWAGGER_RELATIVE_URL}-json`
);
expect(response.status).toEqual(404);
});

it.each([SWAGGER_RELATIVE_URL, `${SWAGGER_RELATIVE_URL}/`])(
'should serve Swagger UI at "%s"',
async (url) => {
const response = await request(app.getHttpServer()).get(url);
expect(response.status).toEqual(200);
}
);
});

describe('Serve no definitions when raw is an empty array', () => {
const SWAGGER_RELATIVE_URL = '/apidoc';

beforeEach(async () => {
const swaggerDocument = SwaggerModule.createDocument(
app,
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
raw: []
});
await app.init();
});

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

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

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

it.each([SWAGGER_RELATIVE_URL, `${SWAGGER_RELATIVE_URL}/`])(
'should serve Swagger UI at "%s"',
async (url) => {
const response = await request(app.getHttpServer()).get(url);
expect(response.status).toEqual(200);
}
);
});

describe('custom documents endpoints', () => {
const JSON_CUSTOM_URL = '/apidoc-json';
const YAML_CUSTOM_URL = '/apidoc-yaml';
Expand Down
132 changes: 130 additions & 2 deletions e2e/fastify.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe('Fastify Swagger', () => {
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
documentsEnabled: false
raw: false
});

await app.init();
Expand Down Expand Up @@ -170,7 +170,7 @@ describe('Fastify Swagger', () => {
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
swaggerUiEnabled: false,
documentsEnabled: false
raw: false
});

await app.init();
Expand Down Expand Up @@ -204,6 +204,134 @@ describe('Fastify Swagger', () => {
);
});

describe('Serve only JSON definition when raw is ["json"]', () => {
const SWAGGER_RELATIVE_URL = '/apidoc';

beforeEach(async () => {
const swaggerDocument = SwaggerModule.createDocument(
app,
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
raw: ['json']
});
await app.init();
await app.getHttpAdapter().getInstance().ready();
});

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

it('should serve only 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 not serve the YAML definition file', async () => {
const response = await request(app.getHttpServer()).get(
`${SWAGGER_RELATIVE_URL}-yaml`
);
expect(response.status).toEqual(404);
});

it.each([SWAGGER_RELATIVE_URL, `${SWAGGER_RELATIVE_URL}/`])(
'should serve Swagger UI at "%s"',
async (url) => {
const response = await request(app.getHttpServer()).get(url);
expect(response.status).toEqual(200);
}
);
});

describe('Serve only YAML definition when raw is ["yaml"]', () => {
const SWAGGER_RELATIVE_URL = '/apidoc';

beforeEach(async () => {
const swaggerDocument = SwaggerModule.createDocument(
app,
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
raw: ['yaml']
});
await app.init();
await app.getHttpAdapter().getInstance().ready();
});

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

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

it('should serve only 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([SWAGGER_RELATIVE_URL, `${SWAGGER_RELATIVE_URL}/`])(
'should serve Swagger UI at "%s"',
async (url) => {
const response = await request(app.getHttpServer()).get(url);
expect(response.status).toEqual(200);
}
);
});

describe('Serve no definitions when raw is an empty array', () => {
const SWAGGER_RELATIVE_URL = '/apidoc';

beforeEach(async () => {
const swaggerDocument = SwaggerModule.createDocument(
app,
builder.build()
);
SwaggerModule.setup(SWAGGER_RELATIVE_URL, app, swaggerDocument, {
raw: []
});
await app.init();
await app.getHttpAdapter().getInstance().ready();
});

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

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

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

it.each([SWAGGER_RELATIVE_URL, `${SWAGGER_RELATIVE_URL}/`])(
'should serve Swagger UI at "%s"',
async (url) => {
const response = await request(app.getHttpServer()).get(url);
expect(response.status).toEqual(200);
}
);
});

describe('custom documents endpoints', () => {
const JSON_CUSTOM_URL = '/apidoc-json';
const YAML_CUSTOM_URL = '/apidoc-yaml';
Expand Down
8 changes: 5 additions & 3 deletions lib/interfaces/swagger-custom-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ export interface SwaggerCustomOptions {
swaggerUiEnabled?: boolean;

/**
* If `false`, both the Swagger UI and API definitions (JSON and YAML) will be disabled.
* Use this option when you want to completely hide all Swagger-related endpoints.
* If `true`, raw definitions for all formats will be served.
* Alternatively, you can pass an array to specify the formats to be served, e.g., `raw: ['json']` to serve only JSON definitions.
* If omitted or set to an empty array, no definitions (JSON or YAML) will be served.
* Use this option to control the availability of Swagger-related endpoints.
* Default: `true`.
*/
documentsEnabled?: boolean;
raw?: boolean | Array<'json' | 'yaml'>;

/**
* Url point the API definition to load in Swagger UI.
Expand Down
Loading

0 comments on commit bc6c7ba

Please sign in to comment.