Skip to content

Commit 593f73e

Browse files
committed
Add support for returning Buffer and streams from action
1 parent 2b0251c commit 593f73e

File tree

5 files changed

+97
-11
lines changed

5 files changed

+97
-11
lines changed

src/driver/BaseDriver.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ValidatorOptions} from "class-validator";
2-
import {ClassTransformOptions} from "class-transformer";
2+
import {ClassTransformOptions, classToPlain} from "class-transformer";
33

44
import {HttpError} from "../http-error/HttpError";
55
import {CurrentUserChecker} from "../CurrentUserChecker";
@@ -127,6 +127,25 @@ export abstract class BaseDriver {
127127
// Protected Methods
128128
// -------------------------------------------------------------------------
129129

130+
protected transformResult(result: any, action: ActionMetadata, options: Action): any {
131+
// check if we need to transform result
132+
const shouldTransform = (this.useClassTransformer && result != null) // transform only if enabled and value exist
133+
&& result instanceof Object // don't transform primitive types (string/number/boolean)
134+
&& !(
135+
result instanceof Buffer // don't transform binary data
136+
||
137+
result.pipe instanceof Function // don't transform streams
138+
);
139+
140+
// transform result if needed
141+
if (shouldTransform) {
142+
const options = action.responseClassTransformOptions || this.classToPlainTransformOptions;
143+
result = classToPlain(result, options);
144+
}
145+
146+
return result;
147+
}
148+
130149
protected processJsonError(error: any) {
131150
if (!this.isDefaultErrorHandlingEnabled)
132151
return error;

src/driver/express/ExpressDriver.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,8 @@ export class ExpressDriver extends BaseDriver {
226226
*/
227227
handleSuccess(result: any, action: ActionMetadata, options: Action): void {
228228

229-
// check if we need to transform result and do it
230-
if (result && result instanceof Object && this.useClassTransformer) {
231-
const options = action.responseClassTransformOptions || this.classToPlainTransformOptions;
232-
result = classToPlain(result, options);
233-
}
229+
// transform result if needed
230+
result = this.transformResult(result, action, options);
234231

235232
// set http status code
236233
if (result === undefined && action.undefinedResultCode && action.undefinedResultCode instanceof Function) {
@@ -297,6 +294,12 @@ export class ExpressDriver extends BaseDriver {
297294
}
298295
options.next();
299296
}
297+
else if (result instanceof Buffer) {
298+
options.response.send(result);
299+
}
300+
else if (result.pipe instanceof Function) {
301+
result.pipe(options.response);
302+
}
300303
else { // send regular result
301304
if (action.isJsonTyped) {
302305
options.response.json(result);

src/driver/koa/KoaDriver.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,8 @@ export class KoaDriver extends BaseDriver {
209209
*/
210210
handleSuccess(result: any, action: ActionMetadata, options: Action): void {
211211

212-
// check if we need to transform result and do it
213-
if (this.useClassTransformer && result && result instanceof Object) {
214-
const options = action.responseClassTransformOptions || this.classToPlainTransformOptions;
215-
result = classToPlain(result, options);
216-
}
212+
// transform result if needed
213+
result = this.transformResult(result, action, options);
217214

218215
// set http status code
219216
if (result === undefined && action.undefinedResultCode && action.undefinedResultCode instanceof Function) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import "reflect-metadata";
2+
3+
import {createReadStream} from "fs";
4+
import * as path from "path";
5+
import {createExpressServer, createKoaServer, getMetadataArgsStorage} from "../../src/index";
6+
import {assertRequest} from "./test-utils";
7+
import {InterceptorInterface} from "../../src/InterceptorInterface";
8+
import {Interceptor} from "../../src/decorator/Interceptor";
9+
import {UseInterceptor} from "../../src/decorator/UseInterceptor";
10+
import {Controller} from "../../src/decorator/Controller";
11+
import {Get} from "../../src/decorator/Get";
12+
import {Action} from "../../src/Action";
13+
import {ContentType} from "../../src/decorator/ContentType";
14+
const chakram = require("chakram");
15+
const expect = chakram.expect;
16+
17+
describe("special result value treatment", () => {
18+
19+
const rawData = [0xFF, 0x66, 0xAA, 0xCC];
20+
21+
before(() => {
22+
23+
// reset metadata args storage
24+
getMetadataArgsStorage().reset();
25+
26+
@Controller()
27+
class HandledController {
28+
29+
@Get("/stream")
30+
@ContentType("text/plain")
31+
getStream() {
32+
return createReadStream(path.resolve(__dirname, "../../../../test/resources/sample-text-file.txt"));
33+
}
34+
35+
@Get("/buffer")
36+
getBuffer() {
37+
return new Buffer(rawData);
38+
}
39+
}
40+
41+
});
42+
43+
let expressApp: any, koaApp: any;
44+
before(done => expressApp = createExpressServer().listen(3001, done));
45+
after(done => expressApp.close(done));
46+
before(done => koaApp = createKoaServer().listen(3002, done));
47+
after(done => koaApp.close(done));
48+
49+
describe("should pipe stream to response", () => {
50+
assertRequest([3001, 3002], "get", "stream", response => {
51+
expect(response).to.be.status(200);
52+
expect(response).to.have.header("content-type", (contentType: string) => {
53+
expect(contentType).to.match(/text\/plain/);
54+
});
55+
expect(response.body).to.be.equal("Hello World!");
56+
});
57+
});
58+
59+
describe("should send raw binary data", () => {
60+
assertRequest([3001, 3002], "get", "buffer", response => {
61+
expect(response).to.be.status(200);
62+
expect(response).to.have.header("content-type", "application/octet-stream");
63+
expect(response.body).to.be.equal(new Buffer(rawData).toString());
64+
});
65+
});
66+
});

test/resources/sample-text-file.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello World!

0 commit comments

Comments
 (0)