Covid19 API com Flutter, Mobx e Modular (parte 1)
Em tempos difíceis que estamos vivendo com a epidemia do coronavírus, pode ser uma oportunidade para aprimorar habilidades e avançar nos estudos. #fiqueemcasa
A proposta deste artigo é construir uma aplicação em Flutter que consome os dados da API COVID19.
Realizaremos também a integração com MobX para gestão do estado e o Modular para injeção de dependências.
Se preferir, fiz a integração dessa API com Angular. O tutorial e o código estão aqui.
Contextualizando
Comecei a programar em Flutter no final do ano passado (2019) e a princípio estranhei a forma como declaramos os Widgets e os abre e fecha de parênteses sem fim…rsrs
No entanto, o que mais me incomodou naquela época foi a discussão referente a Blocs. Como a maioria dos exemplos para iniciantes não separam as regras de negócio da view, tudo ficou um pouco mais nebuloso.
O meu objetivo com esse tutorial é mostrar que, mesmo para exemplos simples, como esse de consumir uma API, é possível trabalhar de forma mais organizada o código.
Assim, a justificativa em utilizar o Modular se dá pois a biblioteca “permite gerenciar a injeção de dependências e rotas em apenas um arquivo por módulo”.
Ainda de acordo com a documentação, o foco da biblioteca é baseado em:
- Gerência Automática de Memória.
- Injeção de Dependências.
- Controle de Rotas Dinâmicas.
- Modularização de Código.
Superado essa fase, outro aspecto da implementação é gerenciar o estado da aplicação, ou seja, entre outras coisas, a comunicação dos dados com a UI. Para isso a escolha se deu com o MobX, que é uma biblioteca que facilita gerenciar reativamente o estado dos aplicativos, utilizando observáveis, ações e reações.
Passos iniciais
Caso você seja iniciante no framework, recomendo o link para instalação do framework.
Após a instalação, no terminal, posicione o cursor no diretório de sua preferência e informe o seguinte comando:
Será iniciado a criação do projeto na pasta flutter_covid19 com todos os artefatos para iniciarmos a codificação da nossa aplicação.
Após o término, vamos abrir o projeto utilizando o Visual Studio Code.
Informe os seguintes comando para isso:
cd flutter_covid19
code .
Instalando as dependências
Na pasta raiz encontre o arquivo pubspec.yaml. Ele traz a relação das dependências do projeto. É nesse arquivo que incluímos, por exemplo, as bibliotecas, caminhos dos arquivos estáticos ou dependências de desenvolvimento.
Incluímos 4 pacotes na seção dependencies (lembre-se de respeitar o recuo…).
dio : Responsável pelas requisições REST
flutter_modular: Injeção de dependências, rotas…
flutter_mobx e mobx: responsáveis pela implementação do MOBX
Na seção dev_dependencies incluímos o mobx_codgen que irá gerar automaticamente os artefatos com base nas anotações que codificarmos no controle e o build_runner que auxilia todo esse processo.
Ao salvar, a IDE executa o comando flutter packages get que realiza o download das dependências.
Separando os papeis
Em lib, vamos criar 4 pastas:
- app : Salvaremos o módulo e o Widget principal
- models : Classes que representam as informações da API
- pages : Uis e controladores (regras)
- repositories : Serviço de requisição a API
Com isso, já conseguimos definir um mínimo de organização para o projeto pensando na manutenção do código.
Modelos
Na pasta models vamos criar 2 arquivos, mundo_model.dart e pais_model.dart que respectivamente irão representar as informações da pandemia relativa aos dados globais e de um país em específico.
Após a definição dos atributos e do construtor, codificamos um método estático para mapear os dados retornados da API (fromJson) e também um ajuste para exibir a data em Dart utilizando o DateTime com o método fromMillisecondsSinceEpoch.
O código pais_model.dart classe ficou assim:
Na assinatura da classe herdamos de Mundo, reaproveitando o código para atributos em comum com extends Mundo. Outra diferença do código está no método construtor ao utilizamos o super para inicializar os atributos herdados.
Uma observação também para a forma como recuperamos a imagem da bandeira em urlBandeira: doc[‘countryInfo’][‘flag’], pois na API, esse dado está aninhado em um objeto interno CountryInfo.
Mais informações sobre API em https://github.com/NovelCOVID/API.
Criando o Repositório
Codificaremos a classe que acessa o endpoint da API e os métodos.
Vamos criar o arquivo covidapi_repository.dart na pasta respositories.
Update 20/04
O endereço foi depreciado. Troque a url para a versão 2 da API:
Instanciamos o objeto _dio e declaramos o endereço da API para o atributo url.
No método getMundo criamos um objeto response, invocamos o método HTTP get, passando a url e concatenando com ‘/all’, conforme a documentação do endpoint.
Em seguida verificamos o código do status para decidir uma exceção em caso de diferente de 200, lançamos o erro.
Senão, mapeamos o conteúdo da resposta para o método estático definido no modelo em Mundo.fromJson(response.data).
A implementação do método getPais é bem parecida. Informamos um parâmetro opcional com as chaves em {String pais} e concatenamos com a url.
No entanto, dessa vez mapeamos o retorno da requisição para país em Pais.fromJson(response.data)
Dessa forma, finalizamos a classe responsável pelas requisições.
Mapeamento de Rotas e Injeção
Vamos finalizar essa primeira parte escrevendo as classes que definem as rotas e o start da aplicativo.
Na pasta app crie os arquivos app_module.dart e app_widget.dart.
Em app_widget codificamos a classe AppWidget
Nesse Widget setamos algumas configurações globais, como retirar aquele banner de debug (debugShowCheckedModeBanner) e informar que o Modular gerenciará as rotas em navigatorKey e onGenerateRoute.
Em app_module.dart fazemos:
Estendemos a classe AppModule para MainModule, assim devemos implementar 3 métodos.
binds => Classes que vamos fazer a injeção de dependência. Já incluímos o repositório da API.
routers => Definiremos as rotas. A ‘/’ é a rota inicial. Colocamos uma tela de abertura SplashPage() que será apresentada na parte 2.
bootstrap => O widget principal. No nosso caso, AppWidget(), que é foi a classe criada anteriormente.
Na parte 2, vamos finalizar o desenvolvimento, construindo as interfaces UI e o controlador.
Até +.