Skip to content

Commit 804aa50

Browse files
feat(): create sse component, update docs
1 parent cd1a85d commit 804aa50

File tree

4 files changed

+47
-28
lines changed

4 files changed

+47
-28
lines changed
Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,27 @@
11
### Server-Sent Events
22

3-
You can enable Server-Sent events on a route with Nest. This can be used to push real-time updates to your client using HTTP. More informations about this specification can be found [on the whatwg website](https://html.spec.whatwg.org/multipage/server-sent-events.html).
3+
Server-Sent Events (SSE) is a server push technology enabling a client to receive automatic updates from a server via HTTP connection. Each notification is sent as a block of text terminated by a pair of newlines (learn more [here](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)).
44

55
#### Usage
66

7-
In this example, we set a route named `/sse` that will allow you to propagate real time updates. These events can be listened to using the Javascript [EventSource API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource). On the `/` route, for the sake of the example, we're logging the received data in the browser's console.
7+
To enable Server-Sent events on a route (route registered within a **controller class**), annotate the method handler with the `@Sse()` decorator.
88

9-
Note the `@Sse` decorator that hooks the Server-Sent events mechanism on the chosen path:
10-
11-
```
12-
@Controller()
13-
export class AppController {
14-
@Get()
15-
getHello(): string {
16-
return `
17-
<script type="text/javascript">
18-
const ee = new EventSource('/sse')
19-
ee.onmessage = ({data}) => {
20-
console.log('New message', JSON.parse(data))
21-
}
22-
</script>
23-
`;
24-
}
25-
26-
@Sse('/sse')
27-
sse(): Observable<MessageEvent> {
28-
return interval(1000).pipe(map((_) => ({ data: { hello: 'world' } })));
29-
}
9+
```typescript
10+
@Sse('sse')
11+
sse(): Observable<MessageEvent> {
12+
return interval(1000).pipe(map((_) => ({ data: { hello: 'world' } })));
3013
}
3114
```
3215

33-
The events are sent via an Observable emitting a `MessageEvent`. The MessageEvent should respect the following interface to match the specification:
16+
> info **Hint** The `@Sse()` decorator is imported from the `@nestjs/common`, while `Observable`, `interval`, `and map` are imported from the `rxjs` package.
3417
35-
```
18+
> warning **Warning** Server-Sent Events routes must return an `Observable` stream.
19+
20+
In the example above, we defined a route named `sse` that will allow us to propagate real-time updates. These events can be listened to using the [EventSource API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
21+
22+
The `sse` method returns an `Observable` that emits multiple `MessageEvent` (in this example, it emits a new `MessageEvent` every second). The `MessageEvent` object should respect the following interface to match the specification:
23+
24+
```typescript
3625
export interface MessageEvent {
3726
data: string | object;
3827
id?: string;
@@ -41,4 +30,17 @@ export interface MessageEvent {
4130
}
4231
```
4332

44-
You can find a working example in the [Nest repository](https://github.com/nestjs/nest/tree/master/sample/28-sse).
33+
With this in place, we can now create an instance of the `EventSource` class in our client-side application, passing the `/see` (which is a route string matching what we have passed into the `@Sse()` decorator above) as a constructor argument.
34+
35+
`EventSource` instance opens a persistent connection to an HTTP server, which sends events in `text/event-stream` format. The connection remains open until closed by calling `EventSource.close()`.
36+
37+
Once the connection is opened, incoming messages from the server are delivered to your code in the form of events. If there is an event field in the incoming message, the triggered event is the same as the event field value. If no event field is present, then a generic `message` event is fired ([source](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)).
38+
39+
```javascript
40+
const eventSource = new EventSource('/sse');
41+
eventSource.onmessage = ({ data }) => {
42+
console.log('New message', JSON.parse(data));
43+
};
44+
```
45+
46+
You can find a working example [here](https://github.com/nestjs/nest/tree/master/sample/28-sse).

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
ChangeDetectionStrategy,
33
Component,
44
Input,
5-
OnInit,
5+
OnInit
66
} from '@angular/core';
77
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
88
import { filter } from 'rxjs/operators';
@@ -98,7 +98,8 @@ export class MenuComponent implements OnInit {
9898
{ title: 'HTTP module', path: '/techniques/http-module' },
9999
{ title: 'Model-View-Controller', path: '/techniques/mvc' },
100100
{ title: 'Performance (Fastify)', path: '/techniques/performance' },
101-
],
101+
{ title: 'Server-Sent Events', path: '/techniques/server-sent-events' }
102+
],
102103
},
103104
{
104105
title: 'GraphQL',
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { BasePageComponent } from '../../page/page.component';
3+
4+
@Component({
5+
selector: 'app-sse',
6+
templateUrl: './server-sent-events.component.html',
7+
changeDetection: ChangeDetectionStrategy.OnPush,
8+
})
9+
export class ServerSentEventsComponent extends BasePageComponent {}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { PerformanceComponent } from './performance/performance.component';
1515
import { QueuesComponent } from './queues/queues.component';
1616
import { SecurityComponent } from './security/security.component';
1717
import { SerializationComponent } from './serialization/serialization.component';
18+
import { ServerSentEventsComponent } from './server-sent-events/server-sent-events.component';
1819
import { SqlComponent } from './sql/sql.component';
1920
import { TaskSchedulingComponent } from './task-scheduling/task-scheduling.component';
2021
import { ValidationComponent } from './validation/validation.component';
@@ -108,6 +109,11 @@ const routes: Routes = [
108109
path: 'hot-reload',
109110
redirectTo: '/recipes/hot-reload',
110111
},
112+
{
113+
path: 'server-sent-events',
114+
component: ServerSentEventsComponent,
115+
data: { title: 'Server-Sent Events' },
116+
},
111117
];
112118

113119
@NgModule({
@@ -129,6 +135,7 @@ const routes: Routes = [
129135
ValidationComponent,
130136
CachingComponent,
131137
SerializationComponent,
138+
ServerSentEventsComponent
132139
],
133140
})
134141
export class TechniquesModule {}

0 commit comments

Comments
 (0)