Consumindo APIs com Flutter e Redux

Carlos Lira
Nov 26 · 7 min read

Por Carlos Lira

Por que meus aplicativos devem consumir APIs com Flutter e Redux?

A maioria das pessoas só conhece o Redux quando esbarra no React, e acaba entendendo que sua arquitetura é uma parte do React… Isso é muito triste, porque o Redux é incrível! É uma arquitetura de fluxo de dados unidirecional criada para qualquer interface do usuário, que permite anexar funções como enviar uma requisição HTTP a uma API e despachar a resposta ao seu alterador de estado — discutiremos isso um pouco mais adiante — mas é ainda mais útil quando combinado com uma implementação de exibição declarativa que pode inferir as atualizações da interface do usuário a partir de alterações de estado (como o Flutter!)

Redux Middlewares

Uma breve explicação antes de prosseguirmos. O Redux permite incluir funções personalizadas que processam a ação antes de ser enviada para o próximo dispatcher e, eventualmente, para o reducer para formar o novo estado. Essas funções são chamadas de middleware.

Eles são realmente úteis em muitos cenários; por exemplo: você faz chamadas para uma API e a resposta dessas chamadas afeta o estado do seu aplicativo. O que você deveria fazer? Primeiro de tudo, use o Redux, isso fará com que os dados importantes para a interface do usuário sejam centralizados em um único estado e estejam disponíveis sempre que você desejar. O Flutter usa o Dart e, nesse caso, existem dois middlewares que nos ajudarão: redux_api_middleware e redux_thunk.

O middleware thunk original é uma implementação em javascript que pode ser encontrada aqui. O middleware thunk que usaremos foi portado para Dart por Brian Egan. O middleware original da API também é uma implementação em javascript que pode ser encontrada aqui. O middleware da API foi portado por mim para o Dart (confira no meu GitHub :D)

O middleware thunk permite enviar chamadas assíncronas, o que é perfeito para o middleware da API, porque as solicitações HTTP também são assíncronas. O middleware chama a API e envia a resposta ao seu reducer possibilitando identificar o próximo estado do aplicativo.

Também adicionaremos um middleware de log para que possamos ver facilmente o tráfego passando por nosso middleware.

Neste tutorial, abordaremos estes tópicos:

  1. Criar um novo projeto Flutter.
  2. Adicionar as dependências.
  3. Criar os arquivos relacionados ao Redux, como ações e redutores.
  4. Editar o ponto de entrada do aplicativo.
  5. Adicionar um registrador de solicitações de API.
  6. Criar as rotas do aplicativo.
  7. Criar os componentes da interface do usuário.

Neste tutorial, usarei a extensão VSCode do Flutter. Dito isto, vamos codar!

Crie um novo projeto Flutter

  1. Invoque View > Command Palette.
  2. Digite “flutter e selecione Flutter: New Project.
  3. Digite um nome de projeto, como myapp, e pressione Enter.
  4. Crie ou selecione o diretório pai para a nova pasta do projeto.
  5. Aguarde a conclusão da criação do projeto e a exibição do arquivo main.dart.

Adicione as dependências

Seu aplicativo Flutter procura suas dependências na seção pubspec.yaml. Vamos mudar este arquivo para adicionar nossas próprias dependências. Para isso, vamos precisar do redux , do flutter_redux , do redux_thunk e do redux_api_middleware .

Como se sabe, a comunidade Flutter está crescendo todos os dias, assim como o número de bibliotecas e componentes disponíveis. Essas bibliotecas e componentes da comunidade potencialmente têm vulnerabilidades que podem ser herdadas pelo aplicativo, portanto, seja cuidadoso.

Para evitar herdar vulnerabilidades presentes em componentes, tome as devidas precauções antes de utilizá-los: verifique quantas pessoas estão usando estes componentes, use sempre a versão mais atualizada (o que pelo menos em parte garante que eventuais bugs tenham sido corrigidos) e, caso se sinta confortável, faça uma auditoria no código procurando possíveis vulnerabilidades.

Dito isto, no momento em que o escrevi, meu arquivo pubspec.yaml tinha a seguinte aparência:

Crie a estrutura Redux

Primeiro, vamos criar a estrutura de pastas base para o nosso aplicativo. Crie estas pastas na pasta lib: models, actions, reducers e components. Depois disso, sua estrutura de pastas lib deve ficar assim:

lib
├── actions
├── components
├── models
├── reducers
└── main.dart

Os nomes são meio autoexplicativos, mas não custa falar um pouco sobre eles.

A pasta de models é onde está o mapeamento de dados. Gosto de separá-los por módulos; por exemplo: temos um módulo de usuário, portanto, todos os modelos relacionados a esse módulo devem ser criados dentro da pasta de usuário na pasta de models.

A pasta de actions é onde estão nossas ações, eu também gosto de dividi-las por módulos; por exemplo: temos um módulo de usuário, portanto, todas as ações que dizem respeito a esse módulo devem estar em um arquivo user_actions.dart na pasta de actions.

A pasta reducers é onde estão os reducers e também é dividida por módulo. No exemplo que estamos usando (módulo de usuário), todos os reducers relacionados a esse módulo devem estar em um arquivo user_reducer.dart na pasta de reducers.

A pasta de components é onde estarão nossos componentes, e a maneira como gosto de organizá-la é certamente controversa: assim como todas as outras pastas, também separo os componentes como módulos, em vez da separação típica de apresentação e contêineres. Não sou contra, apenas prefiro a organização dos módulos. Caso prefira, é possível usar a abordagem de apresentação e contêineres, mas neste artigo usarei a separação de módulos.

Crie o usuário e os modelos de estado do usuário

Usarei a abordagem descrita acima, mas fique à vontade para modificá-la como desejar. Crie uma pasta de user na pasta de models e, em seguida, crie um user.dart e um user_state.dart na pasta de user.

Agora crie um user_state.dart na pasta user.

Crie o modelo de estado do aplicativo

O modelo de estado do aplicativo centraliza todo o estado do aplicativo em um singleton, incluindo o estado do usuário descrito acima. Crie um app_state.dart na pasta models.

Crie alguns RSAAs

As ações de chamada à API padrão do Redux, também conhecidas como RSAAs, são o tipo de ação que o redux_api_middleware intercepta e contém a definição de solicitação. Usaremos uma amostra de API fornecida pelo JSONPlaceholder para este tutorial. Crie um user_actions.dart na pasta actions.

Crie o reducer de usuário

As RSAAs despacham Ações Padrão de Fluxo, também conhecidas como FSAs, que contêm o tipo despachado, a carga útil da resposta e um erro (caso ocorra). Esse FSA será enviado ao redutor do usuário, o qual retornará um novo estado com base no FSA. Crie um user_reducer.dart na pasta reducers.

Crie o reducer principal

O reducer principal combina todos os reducers para que eles possam ser acessados ​​no singleton do AppState. Crie um app_reducer.dart na pasta reducers.

Edite o arquivo main.dart

Esta seção é bastante simples: nosso método de compilação retornará um StoreProvider do pacote Redux que gerenciará nossa store e a deixará acessível através dos StoreConnectors sobre os quais falaremos a seguir. Edite o arquivo main.dart.

É possível notar que o middleware de log, as rotas do aplicativo e as telas estão ausentes. Vamos consertar isso.

Crie o middleware de log

Isso será muito simples, é um middleware que intercepta FSAs e imprime seu tipo, carga útil e erro. Crie um arquivo logger.dart na pasta lib.

Crie as rotas do aplicativo

Esta é simplesmente uma maneira de organizar nossas rotas nomeadas. Crie um routes.dart na pasta lib.

Crie a tela de usuários

A tela de usuários é um StatelessWidget porque não precisa de um estado próprio. Ele se conecta à store e tem acesso a todos os dados do aplicativo, precisamos apenas mapear o estado em props, ainda não tenho certeza sobre esse termo, mas é o que estou usando, uma vez que o construtor do StoreConnector deve ter um parâmetro props que possa ser usado por meio de nosso componente e, como veremos, também mapearemos as ações para que possamos usá-las facilmente. Crie um users_screen.dart na pasta components/users.

Finalmente…

Crie a tela de detalhes do usuário

A tela de detalhes do usuário é um StatelessWidget porque também não precisa de um estado próprio. Ele chama dinamicamente o middleware da API e despacha os estados, e a interface do usuário reflete isso perfeitamente. Crie um user_details_screen.dart na pasta components/users.

Hora de executar seu aplicativo e se divertir…

Dica de segurança

A maioria das APIs que consumimos em aplicativos é autenticada de alguma forma. E não queremos perguntar sempre as credenciais do usuário. Portanto, queremos armazenar essas credenciais para facilitar a nossa experiência e a experiência do usuário; no entanto isso traz alguns riscos, pois outros aplicativos podem ter acesso a esse arquivo específico, tornando-se um possível vetor de ataque. Existe uma biblioteca chamada flutter_secure_storage que resolve esse problema. Ele usa o Keychain nativo no IOS e o KeyStore no Android. Então, sim… Use-o se estiver armazenando credenciais do usuário.

Conclusão

Esqueça a ideia de que o Redux é um pacote do React! Use-o sempre que puder, facilitou minha vida e espero ter facilitado a sua também: D

Sei que o Flutter é uma nova tecnologia, mas é extremamente produtiva, fácil de trabalhar e acredito que terá um futuro brilhante. Fiquei surpreso com o Dart, é muito fácil aprender e divertido codificar, me lembra um pouco de javascript.

O projeto completo estará no meu GitHub. Você pode entrar em contato comigo no meu LinkedIn se precisar de ajuda, criticar ou apenas quiser falar sobre seus problemas.

Se você gostou desta leitura, conte-me nos comentários e lembre-se da coisa mais importante: gifs de gatos recebem palmas…

SideChannel-BR

Notícias e análises sobre segurança da informação produzidas pela equipe e por amigos da Tempest Security Intelligence

Carlos Lira

Written by

SideChannel-BR

Notícias e análises sobre segurança da informação produzidas pela equipe e por amigos da Tempest Security Intelligence