Skip to content

Commit 2ab4f34

Browse files
authored
Merge pull request #286 from elementar/directly-calling-response
Directly calling response
2 parents f506b18 + 9e4efcf commit 2ab4f34

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ export class UserController {
246246

247247
#### Using Request and Response objects
248248

249-
You can use framework's request and response objects this way:
249+
You can use framework's request and response objects directly. If you want to handle the response by yourself,
250+
just make sure you return the response object itself from the action.
250251

251252
```typescript
252253
import {Controller, Req, Res, Get} from "routing-controllers";
@@ -256,7 +257,7 @@ export class UserController {
256257
257258
@Get("/users")
258259
getAll(@Req() request: any, @Res() response: any) {
259-
response.send("Hello response!");
260+
return response.send("Hello response!");
260261
}
261262
262263
}
@@ -274,7 +275,7 @@ export class UserController {
274275
275276
@Get("/users")
276277
getAll(@Req() request: Request, @Res() response: Response) {
277-
response.send("Hello response!");
278+
return response.send("Hello response!");
278279
}
279280
280281
}

src/driver/express/ExpressDriver.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export class ExpressDriver extends BaseDriver {
105105
const action: Action = { request, response, next };
106106
try {
107107
const checkResult = this.authorizationChecker(action, actionMetadata.authorizedRoles);
108-
108+
109109
const handleError = (result: any) => {
110110
if (!result) {
111111
let error = actionMetadata.authorizedRoles.length === 0 ? new AuthorizationRequiredError(action) : new AccessDeniedError(action);
@@ -114,7 +114,7 @@ export class ExpressDriver extends BaseDriver {
114114
next();
115115
}
116116
};
117-
117+
118118
if (isPromiseLike(checkResult)) {
119119
checkResult
120120
.then(result => handleError(result))
@@ -230,6 +230,12 @@ export class ExpressDriver extends BaseDriver {
230230
*/
231231
handleSuccess(result: any, action: ActionMetadata, options: Action): void {
232232

233+
// if the action returned the response object itself, short-circuits
234+
if (result && result === options.response) {
235+
options.next();
236+
return;
237+
}
238+
233239
// transform result if needed
234240
result = this.transformResult(result, action, options);
235241

src/driver/koa/KoaDriver.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export class KoaDriver extends BaseDriver {
8181
const checkResult = actionMetadata.authorizedRoles instanceof Function ?
8282
getFromContainer<RoleChecker>(actionMetadata.authorizedRoles).check(action) :
8383
this.authorizationChecker(action, actionMetadata.authorizedRoles);
84-
84+
8585
const handleError = (result: any) => {
8686
if (!result) {
8787
let error = actionMetadata.authorizedRoles.length === 0 ? new AuthorizationRequiredError(action) : new AccessDeniedError(action);
@@ -90,7 +90,7 @@ export class KoaDriver extends BaseDriver {
9090
return next();
9191
}
9292
};
93-
93+
9494
if (isPromiseLike(checkResult)) {
9595
return checkResult
9696
.then(result => handleError(result))
@@ -213,6 +213,11 @@ export class KoaDriver extends BaseDriver {
213213
*/
214214
handleSuccess(result: any, action: ActionMetadata, options: Action): void {
215215

216+
// if the action returned the context or the response object itself, short-circuits
217+
if (result && (result === options.response || result === options.context)) {
218+
return options.next();
219+
}
220+
216221
// transform result if needed
217222
result = this.transformResult(result, action, options);
218223

@@ -227,7 +232,7 @@ export class KoaDriver extends BaseDriver {
227232
} else if (action.successHttpCode) {
228233
options.response.status = action.successHttpCode;
229234
}
230-
235+
231236
if (action.redirect) { // if redirect is set then do it
232237
if (typeof result === "string") {
233238
options.response.redirect(result);
@@ -238,7 +243,7 @@ export class KoaDriver extends BaseDriver {
238243
}
239244
} else if (action.renderedTemplate) { // if template is set then render it // TODO: not working in koa
240245
const renderOptions = result && result instanceof Object ? result : {};
241-
246+
242247
this.koa.use(async function (ctx: any, next: any) {
243248
await ctx.render(action.renderedTemplate, renderOptions);
244249
});
@@ -275,7 +280,7 @@ export class KoaDriver extends BaseDriver {
275280
options.response.body = result;
276281
}
277282
}
278-
283+
279284
// apply http headers
280285
Object.keys(action.headers).forEach(name => {
281286
options.response.set(name, action.headers[name]);

test/functional/action-params.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {assertRequest} from "./test-utils";
66
import {User} from "../fakes/global-options/User";
77
import {Controller} from "../../src/decorator/Controller";
88
import {Get} from "../../src/decorator/Get";
9+
import {Ctx} from "../../src/decorator/Ctx";
910
import {Req} from "../../src/decorator/Req";
1011
import {Res} from "../../src/decorator/Res";
1112
import {Param} from "../../src/decorator/Param";
@@ -88,6 +89,26 @@ describe("action parameters", () => {
8889
return "<html><body>hello</body></html>";
8990
}
9091

92+
@Get("/users-direct")
93+
getUsersDirect(@Res() response: any): any {
94+
if (typeof response.send === "function")
95+
return response.status(201).contentType("custom/x-sample").send("hi, I was written directly to the response");
96+
else {
97+
response.status = 201;
98+
response.type = "custom/x-sample; charset=utf-8";
99+
response.body = "hi, I was written directly to the response";
100+
return response;
101+
}
102+
}
103+
104+
@Get("/users-direct/ctx")
105+
getUsersDirectKoa(@Ctx() ctx: any): any {
106+
ctx.response.status = 201;
107+
ctx.response.type = "custom/x-sample; charset=utf-8";
108+
ctx.response.body = "hi, I was written directly to the response using Koa Ctx";
109+
return ctx;
110+
}
111+
91112
@Get("/users/:userId")
92113
getUser(@Param("userId") userId: number) {
93114
paramUserId = userId;
@@ -346,6 +367,22 @@ describe("action parameters", () => {
346367
});
347368
});
348369

370+
describe("writing directly to the response using @Res should work", () => {
371+
assertRequest([3001, 3002], "get", "users-direct", response => {
372+
expect(response).to.be.status(201);
373+
expect(response.body).to.be.equal("hi, I was written directly to the response");
374+
expect(response).to.have.header("content-type", "custom/x-sample; charset=utf-8");
375+
});
376+
});
377+
378+
describe("writing directly to the response using @Ctx should work", () => {
379+
assertRequest([3002], "get", "users-direct/ctx", response => {
380+
expect(response).to.be.status(201);
381+
expect(response.body).to.be.equal("hi, I was written directly to the response using Koa Ctx");
382+
expect(response).to.have.header("content-type", "custom/x-sample; charset=utf-8");
383+
});
384+
});
385+
349386
describe("@Param should give a param from route", () => {
350387
assertRequest([3001, 3002], "get", "users/1", response => {
351388
expect(paramUserId).to.be.equal(1);

0 commit comments

Comments
 (0)