Skip to content

Commit 52f8c45

Browse files
Merge pull request #1700 from jmcdo29/docs/send-file
docs(streams): adds docs for streaming files with `StreamableFiles`
2 parents 943c1da + e26a215 commit 52f8c45

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

content/techniques/streaming-files.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
### Streaming Files
2+
3+
There won't always be a time where you're sending back JSON or string responses. There may be times where you'd like to send back a file from the server to the client. To do this with Nest, normally you'd do te following:
4+
5+
```ts
6+
@Controller('file')
7+
export class FileController {
8+
@Get()
9+
getFile(@Res() res: Response) {
10+
const file = createReadStream(join(process.cwd(), 'package.json'));
11+
file.pipe(res);
12+
}
13+
}
14+
```
15+
16+
to manage sending the file back. This is still doable in Nest, by injecting `@Res()` in the controller, but in doing so you end up losing access to your post-controller interceptor logic. To handle this, you can return a `StreamableFile` instance and under the hood Nest will take care of piping the response.
17+
18+
#### Streamable File
19+
20+
A `StreamableFile` is as class that holds onto the stream that is to be returned. To create a new `StreamableFile`, you can pass either a `Buffer` or a `Stream` to the `StreamableFile` constructor.
21+
22+
> info **hint** The `StreamableFile` class can be imported from `@nestjs/common`.
23+
24+
#### Cross Platform Support
25+
26+
Fastify, by default, can support sending files without needing to `stream.pipe(res)`, so you don't need to use the `StreamableFile` class. However, Nest supports the use of `StreamableFile` in both platform types, so if you end up switching between Express and Fastify there's no need to worry about compatibility between the two engines.
27+
28+
#### Example
29+
30+
```ts
31+
import { Controller, Get, StreamableFile } from '@nestjs/common';
32+
import { createReadStream } from 'fs';
33+
import { join } from 'path';
34+
35+
@Controller('file')
36+
export class FileController {
37+
@Get()
38+
getFile(): StreamableFile {
39+
const file = createReadStream(join(process.cwd(), 'package.json'));
40+
return new StreamableFile(file);
41+
}
42+
}
43+
```
44+
45+
This is of course a simple example of returning the `package.json` as a file instead of a JSON, but the idea extends out naturally to images, documents, and any other file type.
46+

src/app/homepage/menu/menu.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export class MenuComponent implements OnInit {
9595
{ title: 'Events', path: '/techniques/events' },
9696
{ title: 'Compression', path: '/techniques/compression' },
9797
{ title: 'File upload', path: '/techniques/file-upload' },
98+
{ title: 'Streaming Files', path: '/techniques/streaming-files' },
9899
{ title: 'HTTP module', path: '/techniques/http-module' },
99100
{ title: 'Session', path: '/techniques/session' },
100101
{ title: 'Model-View-Controller', path: '/techniques/mvc' },
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
import { ChangeDetectionStrategy, Component } from '@angular/core';
3+
import { BasePageComponent } from '../../page/page.component';
4+
5+
@Component({
6+
selector: 'app-streaming-files',
7+
templateUrl: './streaming-files.component.html',
8+
changeDetection: ChangeDetectionStrategy.OnPush,
9+
})
10+
export class StreamingFilesComponent extends BasePageComponent {}

src/app/homepage/pages/techniques/techniques.module.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { SerializationComponent } from './serialization/serialization.component'
1818
import { ServerSentEventsComponent } from './server-sent-events/server-sent-events.component';
1919
import { SessionComponent } from './sessions/sessions.component';
2020
import { SqlComponent } from './sql/sql.component';
21+
import { StreamingFilesComponent } from './streaming-files/streaming-files.component';
2122
import { TaskSchedulingComponent } from './task-scheduling/task-scheduling.component';
2223
import { ValidationComponent } from './validation/validation.component';
2324

@@ -65,6 +66,11 @@ const routes: Routes = [
6566
component: FileUploadComponent,
6667
data: { title: 'File upload' },
6768
},
69+
{
70+
path: 'streaming-files',
71+
component: StreamingFilesComponent,
72+
data: { title: 'Streaming Files' },
73+
},
6874
{
6975
path: 'logger',
7076
component: LoggerComponent,
@@ -151,6 +157,7 @@ const routes: Routes = [
151157
ServerSentEventsComponent,
152158
SessionComponent,
153159
CookiesComponent,
160+
StreamingFilesComponent,
154161
],
155162
})
156163
export class TechniquesModule {}

0 commit comments

Comments
 (0)