# Web Socket

Bind server web socket events to Ngxs store actions.

## Installation

```bash
npm install @ngxs/websocket-plugin --save

# or if you are using yarn
yarn add @ngxs/websocket-plugin
```

## Configuration

Add the `NgxsWebsocketPluginModule` plugin to your root app module:

```ts
import { NgxsModule } from '@ngxs/store';
import { NgxsWebsocketPluginModule } from '@ngxs/websocket-plugin';

@NgModule({
  imports: [
    NgxsModule.forRoot([]),
    NgxsWebsocketPluginModule.forRoot({
      url: 'ws://localhost:4200'
    })
  ]
})
export class AppModule {}
```

The plugin has a variety of options that can be passed:

* `url`: Url of the web socket connection. Can be passed here or by the `ConnectWebsocket` action.
* `typeKey`: Object property that maps the web socket message to a action type. Default: `type`
* `serializer`: Serializer used before sending objects to the web socket. Default: `JSON.stringify`
* `deserializer`: Deserializer used for messages arriving from the web socket. Default: `JSON.parse`

## Usage

Once connected, any message that comes across the web socket will be bound to the state event stream.

Let's assume that a server side web socket sends a message to the client in the following format:

```json
{
  "type": "[Chat] Add message",
  "from": "Artur",
  "message": "Hello NGXS"
}
```

We will want to make an action that corresponds to this web socket message, that will look like:

```ts
export class AddMessage {
  static type = '[Chat] Add message';
  constructor(public from: string, public message: string) {}
}
```

Assume we've got some `messages` state where we store our chat messages:

```ts
export interface Message {
  from: string;
  message: string;
}

@State<Message[]>({
  name: 'messages',
  defaults: []
})
@Injectable()
export class MessagesState {
  @Action(AddMessage)
  addMessage(ctx: StateContext<Message[]>, { from, message }: AddMessage) {
    const state = ctx.getState();
    // omit `type` property that server socket sends
    ctx.setState([...state, { from, message }]);
  }
}
```

We are able to send messages to the server by dispatching the `SendWebSocketMessage` with the payload that you want to send to the server. Let's try it out:

```ts
@Component({ ... })
export class AppComponent {

  constructor(private store: Store) {}

  sendMessage(from: string, message: string) {
    const event = new SendWebSocketMessage({
      type: 'message',
      from,
      message
    });

    this.store.dispatch(event);
  }

}
```

When sending the message, remember the send is accepting a JSON-able object. The socket on the server side would be listening for the `message` event. For example, the server code could be as follows:

```ts
const { Server } = require('ws');
const { createServer } = require('http');

const app = require('express')();

const server = createServer(app);
const ws = new Server({ server });

server.listen(4200);

ws.on('connection', socket => {
  socket.on('message', data => {
    // That's the object that we passed into `SendWebSocketMessage` constructor
    const { type, from, message } = JSON.parse(data);

    if (type === 'message') {
      const event = JSON.stringify({
        type: '[Chat] Add message',
        from,
        message
      });

      // That's the same as `broadcast`
      // we want to send message to all connected
      // to the chat clients
      ws.clients.forEach(client => {
        client.send(event);
      });
    }
  });
});
```

Notice that you have to specify `type` property on server side, otherwise you will get an error - `Type ... not found on message`. If you don't want to use a property called `type` as the key then you can specify your own property name when calling `forRoot`:

```ts
NgxsWebsocketPluginModule.forRoot({
  url: 'ws://localhost:4200',
  typeKey: 'myAwesomeTypeKey'
});
```

In order to kick off our websockets we have to dispatch the `ConnectWebSocket` action. This will typically happen at startup or if you need to authenticate before, after authentication is done. You can optionally pass the URL here.

```ts
@Component({ ... })
export class AppComponent {

  constructor(private store: Store) {}

  ngOnInit() {
    this.store.dispatch(new ConnectWebSocket());
  }

}
```

If you have difficulties with understanding how the plugin works, you can have a look at the data flow diagram below. From one side it seems a little bit complex, but no worries. Just follow the pink data flow that leads to the server-side starting from view:

![NGXS WebSocket data flow](https://2156748680-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L9CoGJCq3UCfKJ7RCUg-2243202597%2Fuploads%2Fgit-blob-ef95887f06524f6d05141c91483b7d570444daeb%2Fngxs-socket-dfd.png?alt=media)

Here is a list of all the available actions you have:

* `ConnectWebSocket`: Dispatch this action when you want to init the web socket. Optionally pass URL here.
* `DisconnectWebSocket`: Dispatch this Action to disconnect a web socket.
* `WebSocketConnected`: Action dispatched when a web socket is connected.
* `WebSocketDisconnected`: Action dispatched when a web socket is disconnected. Use its handler for reconnecting.
* `SendWebSocketMessage`: Send a message to the server.
* `WebsocketMessageError`: Action dispatched by this plugin when an error ocurrs upon receiving a message.
* `WebSocketConnectionUpdated`: Action dispatched by this plugin when a new connection is created on top of an existing one. Existing connection is closing.

In summary - your server-side sockets should send objects that have a `type` property (or another key that you can provide in the `typeKey` property when calling `forRoot`). This plugin will receive a message from the server and dispatch the message as an action with the corresponding `type` value. If the `type` property doesn't match any client-side `@Action` methods (with an Action with the corresponding `static type` property value) then no State will respond to the message.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.ngxs.io/v3.7/plugins/websocket.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
