Server-Sent Events(SSE) com dart (Shelf e Flutter)
Tags: serversentevent, sse, shelf, dart
Published: 2024-04-20 03:55:28

Fala Devs! Com toda certeza você já deve ter tido a necessidade de fazer uma requisição **HTTP**, eu mesmo já escrevi um artigo muito legal que utilizamos o **DIO** como cliente **HTTP** para fazermos requisições a nossa **API** ([https://blog.flutterando.com.br/consumindo-api-utilizando-o-dio-9ec72aeceeaa](https://blog.flutterando.com.br/consumindo-api-utilizando-o-dio-9ec72aeceeaa)).

Entretanto podemos passar por situações que precisamos fazer uma requisição em que o resultado venha de forma gradativa ao cliente, há algumas formas que podemos realizar esta tarefa, a primeira maneira é fazer que nosso cliente fique acessando o servidor continuamente em busca de atualizações, esta técnica é chamada de **pooling**.

Outra forma seria utilizar os WebSockets, eles são talvez a melhor opção quando queremos receber dados de forma gradativa e em tempo real.

Em seu funcionamento é criada uma sessão de comunicação interativa entre o cliente e o servidor, recebendo mensagens em tempo real, funcionando de forma semelhante ao Firestore.

Entretanto ela é uma técnica um pouco custosa e complexa, e as vezes não precisamos de lima solução tão robusta assim, então existe um meio termo?

E a resposta é SIM! O **Server-Sent Events**(popularmente conhecido como **SSE**), um método que funciona de forma semelhante ao **Websocket**, ele basicamente definira uma comunicação em uma API chamada de **EventSource** e esta comunicação se manterá aberta recebendo mensagens de forma gradativa do servidor.

E um bônus, neste artigo não implementaremos apenas o cliente, veremos também como criar o **SSE** do lado do servidor e para isto utilizaremos, é claro, o **DART** para o **backend** com o pacote **SHELF**. [https://pub.dev/packages/shelfv](https://pub.dev/packages/shelfv)

### Servidor

Para isto vamos criar um projeto em branco em Dart. Execute

> **dart create server**

![](https://cdn-images-1.medium.com/max/800/1*Ly6vPvCu-Nh7kjLvHF-Emg.png)

Utilizaremos três pacotes para desenvolver nossa API em Dart:

**Shelf**([https://pub.dev/packages/shelf](https://pub.dev/packages/shelf)) — Pacote responsável por nos ajudar a criar nossos webservers

**Shelf**_router([https://pub.dev/packages/shelf_router](https://pub.dev/packages/shelf_router)) — Pacote que trata a criação de caminhas para os nossos endpoints.

**Eventsource**([https://pub.dev/packages/eventsource](https://pub.dev/packages/eventsource)) — Pacote responsável por implementar o padrão do **eventsource(SSE)** em nossa api.

![](https://cdn-images-1.medium.com/max/800/1*IXlrvLlu5S18nVeEcc-OOg.png)

Com esses três pacotes nosso pubspec deverá ficar da seguinte maneira

A primeira tarefa que faremos é fazer uma implementação do **eventsource** em nosso projeto

![](https://cdn-images-1.medium.com/max/800/1*BQOGeAgvJcupgfl6IClH3Q.png)

Basta adicionarmos a implementação a seguir
{% gist https://gist.github.com/toshiossada/108df238660016f1e7e5703b4fee853d file=eventsource.dart %}

Agora podemos implementar o **entry point** do nossa API que está no **sse.dart**

Primeiramente criamos o método que irá gerar as as mensagens retornadas para o cliente de forma assíncrona, para isto basta quando quisermos retornar alguma informação executar o **publisher.add()** passando um evento de resposta e na hora que finalizar o processamento executar o **publisher.close()**

![](https://cdn-images-1.medium.com/max/800/1*TCziqPoemjjjk66ehwBFLA.png)

Feito isso podemos criar nosso **endpoint** (no caso o **/events**) e passar nosso **EventSourcePublisher** como parâmetro do método **eventSourceHandler**.

![](https://cdn-images-1.medium.com/max/800/1*jR8pKB_Z5E_2ARQ3et292w.png)

{% gist https://gist.github.com/toshiossada/2696a8b8f58d32f43f2afabe98528fb8 file=server.dart %}

E sucesso! Nossa API está pronta, basta executar e ela estará disponível na porta que configuramos (8080), execute:

**dart run**

![](https://cdn-images-1.medium.com/max/800/1*Ip9tTi3jP0ZOQv3wNX79Pg.png)

O resultado será o seguinte:

![](https://cdn-images-1.medium.com/max/800/1*M4LCJ_NPqb7UPOJ7Vd3s9Q.gif)

### Cliente

No nosso aplicativo Flutter só iremos precisar do pacote **eventsource**([https://pub.dev/packages/eventsource](https://pub.dev/packages/eventsource))

Adicione ele no seu pubspec

![](https://cdn-images-1.medium.com/max/800/1*OPs8Dstkqy1j0rl1UC47pQ.png)

Este pacote nos oferece um objeto **Eventsource** que contém o método **conect()** que faz a conexão com a **API** e rebe as mensagens. Como próximo passo devemos criar uma **Stream** e emitir o resultado da mensagem que vem da API nessa **Stream**.

![](https://cdn-images-1.medium.com/max/800/1*aagWA3JNZRLCeOeK7bKU0g.png)

Também devemos criar um getter para conseguir acessar a stream.

![](https://cdn-images-1.medium.com/max/800/1*KmT15VNUOh6dRoH3nRmqPA.png)

A implementação da classe completa deve ficar assim:
{% gist https://gist.github.com/toshiossada/ccd77cf9275200872da0b93298dcf39b file=eventsource_sse_adapter_impl.dart %}
Agora temos uma stream que emite um resultado de um **Map<String, dynamic>** agora em nossa **datasource** podemos escutar essa **stream** para ela fazer o **mapper** do **JSON** para um **Model**

![](https://cdn-images-1.medium.com/max/800/1*eO1LeyBzcetIblfo_mzPTA.png)

No repositório fazemos um **mapper** de **model** para **entity**.

![](https://cdn-images-1.medium.com/max/800/1*Nxnt8gyWdpDwZ2K_Vrdp2w.png)

E por fim na nossa **controller** podemos escutar a **Stream** e mandar atualizar nossa **store** para fazer reatividade na nossa **page**.

![](https://cdn-images-1.medium.com/max/800/1*UTJDJ-Z7l8QRO9XSCLjyAA.png)

Desta forma teremos o seguinte resultado

![](https://cdn-images-1.medium.com/max/800/1*tsZB-XeMG7BPautA0EbjZg.gif)

Legal ne?? muito simples trabalhar com SSE em nossos aplicativos.

O projeto completo pode conferir abaixo
https://github.com/toshiossada/flutter_sse

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/obcg0d2y00yddve9quky.png)


Entre em nosso discord para interagir com a comunidade: https://discord.com/invite/flutterbrasil
https://linktr.ee/flutterbrasil