Skip to content

Commit

Permalink
add useSuccessResponseCode feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
devnev committed Dec 13, 2020
1 parent 839bafc commit 1494a8a
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 15 deletions.
2 changes: 1 addition & 1 deletion packages/cli/src/routeGeneration/routeGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class RouteGenerator {
parameters: parameterObjs,
path: normalisedMethodPath,
security: method.security,
successStatus: method.successStatus || 'undefined',
successStatus: this.options.useSuccessResponseCode && method.successStatus ? method.successStatus : 'undefined',
};
}),
modulePath: this.getRelativeImportPath(controller.location),
Expand Down
6 changes: 6 additions & 0 deletions packages/runtime/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,10 @@ export interface RoutesConfig {
* Authentication Module for express, hapi and koa
*/
authenticationModule?: string;

/**
* When enabled, the `@SuccessResponse` annotations' code is used for responses by default.
* Otherwise, non-empty responses default to 200 and empty responses to 204.
*/
useSuccessResponseCode?: boolean;
}
30 changes: 30 additions & 0 deletions tests/fixtures/express-success-code/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as bodyParser from 'body-parser';
import * as express from 'express';
import * as methodOverride from 'method-override';
import '../controllers/rootController';

import { RegisterRoutes } from './routes';

export const app: express.Express = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(methodOverride());
app.use((req: any, res: any, next: any) => {
req.stringValue = 'fancyStringForContext';
next();
});
RegisterRoutes(app);

// It's important that this come after the main routes are registered
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
const status = err.status || 500;
const body: any = {
fields: err.fields || undefined,
message: err.message || 'An error occurred during the request.',
name: err.name,
status,
};
res.status(status).json(body);
});

app.listen();
41 changes: 41 additions & 0 deletions tests/fixtures/koa-success-code/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as Koa from 'koa';
import * as KoaRouter from '@koa/router';
import '../controllers/rootController';

import '../controllers/deleteController';
import '../controllers/getController';
import '../controllers/headController';
import '../controllers/patchController';
import '../controllers/postController';
import '../controllers/putController';

import '../controllers/methodController';
import '../controllers/parameterController';
import '../controllers/securityController';
import '../controllers/testController';
import '../controllers/validateController';
import '../controllers/noExtendsController';

import * as bodyParser from 'koa-bodyparser';
import { RegisterRoutes } from './routes';

const app = new Koa();
app.use(bodyParser());

const router = new KoaRouter();

RegisterRoutes(router);

// It's important that this come after the main routes are registered
app.use(async (context, next) => {
try {
await next();
} catch (err) {
context.status = err.status || 500;
context.body = err.message || 'An error occurred during the request.';
}
});

app.use(router.routes()).use(router.allowedMethods());

export const server = app.listen();
14 changes: 7 additions & 7 deletions tests/integration/express-server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,27 +378,27 @@ describe('Express Server', () => {
});

describe('NoExtends', () => {
it('should apply custom code from success response', () => {
it('should ignore SuccessResponse code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/customSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
expect(res.status).to.equal(204);
},
202,
204,
);
});

it('should apply enum code from success response', () => {
it('should ignore SuccessResponse enum code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/enumSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
expect(res.status).to.equal(204);
},
202,
204,
);
});

it('should ignore named success response', () => {
it('should ignore SuccessResponse 2XX code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/rangedSuccessResponse`,
(err, res) => {
Expand Down
70 changes: 70 additions & 0 deletions tests/integration/express-success-code.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { expect } from 'chai';
import 'mocha';
import * as request from 'supertest';
import { app } from '../fixtures/express-success-code/server';

describe('Express Server with useSuccessResponseCode', () => {
const basePath = '/v1';

function verifyRequest(verifyResponse: (err: any, res: request.Response) => any, methodOperation: (request: request.SuperTest<any>) => request.Test, expectedStatus = 200) {
return new Promise((resolve, reject) => {
methodOperation(request(app))
.expect(expectedStatus)
.end((err: any, res: any) => {
let parsedError: any;
try {
parsedError = JSON.parse(res.error);
} catch (err) {
parsedError = res.error;
}

if (err) {
reject({
error: err,
response: parsedError,
});
return;
}

verifyResponse(parsedError, res);
resolve();
});
});
}

function verifyGetRequest(path: string, verifyResponse: (err: any, res: request.Response) => any, expectedStatus?: number) {
return verifyRequest(verifyResponse, request => request.get(path), expectedStatus);
}

describe('NoExtends', () => {
it('should apply custom code from success response', () => {
return verifyGetRequest(
basePath + `/NoExtends/customSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
},
202,
);
});

it('should apply enum code from success response', () => {
return verifyGetRequest(
basePath + `/NoExtends/enumSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
},
202,
);
});

it('should ignore 2XX code range from success response', () => {
return verifyGetRequest(
basePath + `/NoExtends/rangedSuccessResponse`,
(err, res) => {
expect(res.status).to.equal(204);
},
204,
);
});
});
});
14 changes: 7 additions & 7 deletions tests/integration/koa-server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,27 +279,27 @@ describe('Koa Server', () => {
});

describe('NoExtends', () => {
it('should apply custom code from success response', () => {
it('should ignore SuccessResponse code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/customSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
expect(res.status).to.equal(204);
},
202,
204,
);
});

it('should apply enum code from success response', () => {
it('should ignore SuccessResponse enum code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/enumSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
expect(res.status).to.equal(204);
},
202,
204,
);
});

it('should ignore named success response', () => {
it('should ignore SuccessResponse 2XX code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/rangedSuccessResponse`,
(err, res) => {
Expand Down
73 changes: 73 additions & 0 deletions tests/integration/koa-success-code.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { expect } from 'chai';
import 'mocha';
import * as request from 'supertest';
import { server } from '../fixtures/koa-success-code/server';

describe('Koa Server with useSuccessResponseCode', () => {
const basePath = '/v1';

function verifyGetRequest(path: string, verifyResponse: (err: any, res: request.Response) => any, expectedStatus?: number) {
return verifyRequest(verifyResponse, request => request.get(path), expectedStatus);
}

function verifyRequest(verifyResponse: (err: any, res: request.Response) => any, methodOperation: (request: request.SuperTest<any>) => request.Test, expectedStatus = 200) {
return new Promise((resolve, reject) => {
methodOperation(request(server))
.expect(expectedStatus)
.end((err: any, res: any) => {
let parsedError: any;

try {
parsedError = JSON.parse(res.error);
} catch (err) {
parsedError = res.error;
}

if (err) {
reject({
error: err,
response: parsedError,
});
return;
}

verifyResponse(parsedError, res);
resolve();
});
});
}

describe('NoExtends', () => {
it('should ignore SuccessResponse code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/customSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
},
202,
);
});

it('should ignore SuccessResponse enum code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/enumSuccessResponseCode`,
(err, res) => {
expect(res.status).to.equal(202);
},
202,
);
});

it('should ignore SuccessResponse 2XX code and use default code', () => {
return verifyGetRequest(
basePath + `/NoExtends/rangedSuccessResponse`,
(err, res) => {
expect(res.status).to.equal(204);
},
204,
);
});
});

it('shutdown server', () => server.close());
});
33 changes: 33 additions & 0 deletions tests/prepare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ const log = async <T>(label: string, fn: () => Promise<T>) => {
metadata,
),
),
log('Express Route Generation with useSuccessResponseCode feature', () =>
generateRoutes(
{
noImplicitAdditionalProperties: 'silently-remove-extras',
authenticationModule: './fixtures/express/authentication.ts',
basePath: '/v1',
entryFile: './fixtures/express-success-code/server.ts',
middleware: 'express',
routesDir: './fixtures/express-success-code',
useSuccessResponseCode: true,
},
undefined,
undefined,
metadata,
),
),
log('Koa Route Generation', () =>
generateRoutes(
{
Expand Down Expand Up @@ -114,6 +130,22 @@ const log = async <T>(label: string, fn: () => Promise<T>) => {
metadata,
),
),
log('Koa Route Generation with useSuccessResponseCode feature', () =>
generateRoutes(
{
noImplicitAdditionalProperties: 'silently-remove-extras',
authenticationModule: './fixtures/koa/authentication.ts',
basePath: '/v1',
entryFile: './fixtures/koa-success-code/server.ts',
middleware: 'koa',
routesDir: './fixtures/koa-success-code',
useSuccessResponseCode: true,
},
undefined,
undefined,
metadata,
),
),
log('Hapi Route Generation', () =>
generateRoutes({
noImplicitAdditionalProperties: 'silently-remove-extras',
Expand All @@ -122,6 +154,7 @@ const log = async <T>(label: string, fn: () => Promise<T>) => {
entryFile: './fixtures/hapi/server.ts',
middleware: 'hapi',
routesDir: './fixtures/hapi',
useSuccessResponseCode: true,
}),
),
log('Custom Route Generation', () =>
Expand Down

0 comments on commit 1494a8a

Please sign in to comment.