Criando um aplicativo em Flutter para consumir uma API de Filmes (TMDb)

Notas de aula do professor Kleber de Oliveira Andrade

Kleber Andrade
Flutter — Comunidade BR

--

Hoje vamos trabalhar a construção de um aplicativo para exibir os filmes. Vale ressaltar que existem muitos aplicativos com esta finalidade, porém nosso foco aqui, é entender como fazer um aplicativo que acesse uma API de filmes. Com este app devemos ser capaz de:

  • Exibe os filmes mais populares do momento (incluindo os ainda não lançados).
  • Exibe os detalhes de um filme selecionado (data de lançamento, sinopse, etc).

Para quem tiver curiosidades, vou deixar aqui a história do cinema.

Entendendo um pouco sobre API

API é o acrônimo de Application Programming Interface ou, em português, Interface de Programação de Aplicativos. Esta interface é o conjunto de padrões de programação que permite a construção de aplicativos e a sua utilização de maneira não tão evidente para os usuários.

API é a “matrix” dos aplicativos, ou seja, uma interface que roda por trás de tudo: enquanto você usufrui de um aplicativo, sistemas desktop ou site, a sua API pode estar conectada a diversos outros sistemas e aplicativos. E tudo isso acontece sem que você perceba.

Segue um vídeo muito legal para você entender mais sobre API

API do The Movie Database (TMDb)

The Movie Database (conhecido como TMDb) é uma base de dados grátis e de código aberto sobre Filmes e Séries de TV. Criado por Travis Bell em 2008, a diferença para as outras base de dados, é que TMDb é atualizado constantemente pela comunidade. Era conhecido apenas por ser uma base de dados de filmes, mas em 2013 foi adicionado a parte de Séries de TV.

Ao contrário do site comercial similar IMDb (propriedade da Amazon.com), que cobra grandes taxas anuais para que os clientes usem os seus dados, o TMDb com o código aberto, significa que muitos sites de cinema e TV podem aceder e usar os seus dados, incluindo utilizadores individuais de Software de gerenciamento de mídia, como Plex, Kodi e outros.

O TMDb ganhou grande interesse quando, no final de fevereiro de 2017, o IMDb deu cerca de duas semanas de antecedência para a remoção completa da funcionalidade de discussões do seu site, incluindo todos os dados históricos de postagens. Após a remoção, um grande número de utilizadores de mensagens encontrou o TMDb, enquanto o programador chefe Bell imediatamente incorporou a funcionalidade de discussões no site para cada campo (filme, série de TV / episódio, empresa, pessoa) para ajudar rapidamente os utilizadores a continuar a conversar sobre filmes e assuntos relacionados com a televisão.

Criando uma conta e chave na TMDb

Acesse o site The Movie Database e clique em entrar > erie uma conta na TMDb e faça login.

Em configurações, clique em API e crie uma nova chave de API para que você possa utilizar no seu projeto. Vou deixar um vídeo em baixo mostrando os passos.

Usando Postman para testar a API

O Postman é uma ferramenta que dá suporte à documentação das requisições feitas pela API. Ele possui ambiente para a documentação, execução de testes de APIs e requisições em geral.

Ao utilizá-lo, você passará a trabalhar com APIs de modo mais eficiente, construindo solicitações rapidamente e, ainda, poderá guardá-las para uso posterior, além de conseguir analisar as respostas enviadas pela API.

Recomendo primeiro você estudar um pouco para aprender a usar a ferramenta Postman. Pode usar este tutorial do enotas, ou ver a série de vídeos abaixo.

Documentação da API

Acesse a documentação da API em https://developers.themoviedb.org/3

Neste projeto iremos utilizar:

Vou utilizar o método de autorização JWT adicionando o token criado

Consultando o endpoint de filmes populares

Consultando o endpoint de detalhes do filme

Criando o aplicativo

Abra o Visual Studio Code, e abra a paleta de comandos F1 e digite: Flutter: New Project

  • Digite o nome do projeto Flutter (movies);
  • Selecione a pasta para criar o projeto Flutter;

Organização do projeto

Nosso projeto, seguirá o modelo MVC (Model-View-Controller) de desenvolvimento.

Vamos observar como as classes se interagem

Dependências

No arquivo pubspec.yaml adicione as seguintes dependências para este projeto.

Sobre as dependências que utilizamos:

  • dartz: para utilizar programação funcional com Dart;
  • dio: cliente HTTP para Dart, que suporta Interceptors, FormData, Cancelamento de Solicitação, Download de Arquivo, Tempo Limite, etc.
  • intl: contém código para lidar com mensagens internacionalizadas / localizadas, formatação e análise de data e número, texto bidirecional e outros problemas de internacionalização.

Criando os Modelos

Sempre que você pensar em manipulação de dados, pense em model. Ele é responsável pela leitura e escrita de dados, e também de suas validações.

Parar criarmos as classes deste projeto, que deve representar o JSON gerado como resposta da API, iremos usar o site quicktype.io (converte JSON em códigos seguros de diversas linguagens).

Foram realizadas pequenas mudanças nas respostas, removendo métodos que não serão utilizados e também corrigindo traduções, como por exemplo, uso de enumeradores substituídos por Strings.

Classe MovieModel

Crie a classe (lib → models → movie_model.dart) que guarda informações da listagem de filmes.

Classe MovieResponseModel

Crie a classe (lib → models → movie_response_model.dart) que guarda informações da página, quantidade de filmes, quantidade de páginas e a lista de MovieModel.

Classe MovieDetailModel

Crie a classe (lib → models → movie_detail_model.dart) que guarda os detalhes de um filme.

Classe MovieGenre

Crie a classe (lib → models → movie_genre.dart) que mapeia os gêneros daquele filme.

Classe ProductionCompanyModel

Crie a classe (lib → models → production_company_model.dart) que mapeia as empresas que produziram o filme.

Classe ProductionCountryModel

Crie a classe (lib → models → production_country_model.dart) que mapeia as cidades.

Classe SpokenLanguageModel

Crie a classe (lib → models → spoken_language_model.dart) que mapeia as linguas faladas.

Criando o Repositório

Repository Pattern é um dos padrões de projeto mais utilizado e conhecidos no desenvolvimento de sistemas. Sua utilização contribui no isolamento da camada de acesso a dados (DAL) com a camada de negócio, mais conhecida como camada de domínio.

O Repository Pattern permite um encapsulamento da lógica de acesso a dados, impulsionando o uso da injeção de dependência (DI) e proporcionando uma visão mais orientada a objetos das interações com a DAL.

Constantes da API

Crie uma classe api (lib → core → api.dart), que irá armazenar constantes necessárias para acessarmos a API TMDb.

Troque o valor da variável kApiKey pela sua chave gerada na página de configurações > API do TMDb.

Classe MovieError

Crie a classe (lib → errors → movie_error.dart) para que possamos ter Exceptions personalizadas em nosso projeto.

Classe MovieRepository

Crie uma classe MovieRepository (lib → repositories → movie_repository.dart), que servirá para se conectar na API do TMDb utilizando dio e converter a resposta em JSON para um objeto (model).

  • Toda comunicação com serviços (Banco de Dados, APIs, Arquivos, etc) utilizam métodos assíncronos.
  • Outro detalhe importante é a parte de tratamento de erros, para isso, usamos try/catch;
  • Para finalizar, observe o uso de Either para retornar o objeto correto ou um erro;

Entendendo um pouco mais sobre HTTP (Hypertext Transfer Protocol)

Os códigos de status de resposta HTTP indicam se uma solicitação HTTP específica foi concluída com êxito. As respostas são agrupadas em cinco classes: respostas informativas, respostas bem-sucedidas, redirecionamentos, erros de clientes e erros de servidores. Os códigos de status são definidos na seção 10 da RFC 2616

Entendendo mais sobre REST (Representational State Transfer)

Criando os Controles

Vamos criar 2 controladores, um para cada página (page), porque o código vai ficar mais organizado e melhor — nada impede de criar um único controlador.

MovieController

Crie a classe MovieController (lib → controllers → movie_controller.dart), que fará o controle dos filmes populares a serem exibidos.

Perceba que nosso método fetchAllMovies, não sobrescreve a lista de filmes, ele simplesmente adiciona:

  • moviesResponseModel.movies.addAll(movie.movies);

Com isso, é possível criar uma lista infinita.

MovieDetailController

Crie a classe MovieDetailController (lib → controllers → movie_detail_controller.dart), que irá fazer o controle dos detalhes dos filmes.

Criando Widgets (Componentes Reutilizáveis)

Sempre que possível, iremos criar alguns componentes para facilitar o desenho das telas e também para reutilizar os widgets em outros projetos.

Classe CenteredMessage

Crie a classe CenteredMessage (lib → widgets → centered_message.dart), que apresentará um Container para exibir uma mensagem e ícone no centro.

Classe CenteredProgress

Crie a classe CenteredProgress (lib → widgets → centered_progress.dart), que apresentará um Container para exibir um circulo animado que indica o progresso do carregamento.

Classe MovieCard

Crie a classe MovieCard (lib → widgets → movie_card.dart), que apresentará um Container para exibir uma imagem do pôster do filme. Essa imagem é acessada em:

Classe Constant

Crie a classe Constant (lib → core → constant.dart), que vai guardar as constantes utilizada no aplicativo.

Classe ChipDate

Crie a classe ChipDate (lib → widgets → chip_date.dart), que vai apresentar um Chip customizado com um ícone de calendário para exibir a data de lançamento do filme.

Classe Rate

Crie a classe Rate (lib → widgets → rate.dart), que vai apresentar uma Row com 2 widgets (Icon e Text) com um ícone de coraçao vermelho e a nota que o filme recebeu até o momento.

Criando as Telas (Views)

Para este projeto, teremos 2 views:

  • MoviePage: tela que exibe um grid de files usando;
  • MovieDetailPage: tela que exibe os detalhes do filme;

Classe MoviePage

Crie a classe MoviePage (lib → pages → movie_page.dart), que definirá a lista de filmes.

  • Na inicialização da página (initState) é chamado o método fetchAllMovie();
  • Durante o carregamento uma tela de loading é exibida;
  • Caso, algum erro tenha acontecido (por exemplo: falta de internet), uma mensagem de erro é exibida no centro da página;
  • O método _initScrollListener configura um Observer para escutar a rolagem da tela, e sempre que a tela chegar no final, é pedido mais filmes para API. Este processo garante uma rolagem infinitas pelos filmes existentes.
  • Quando você clicar no pôster do filme, é chamado a tela de detalhes passando o id do filme (método _openDetailPage).

Classe MovieDetailPage

Crie a classe MovieDetailPage (lib → pages → movie_detail_page.dart), que definirá a página de detalhes de um filme.

  • Passaremos o id do filme selecionado no construtor da página;
  • Na inicialização da página é chamado o método fetchMoviebyId();
  • Durante o carregamento uma tela de loading é exibida;
  • Caso, algum erro tenha acontecido (por exemplo: falta de internet), uma mensagem de erro é exibida no centro da página;

Tema do aplicativo

Crie um arquivo (lib → core → theme_app.dart), que definirá o tema do aplicativo.

Programa principal

Vamos atualizar o arquivo main.dart para que ele instancie a nossa page (view) MoviePage. Neste momento, também podemos definir o tema do aplicativo (theme).

Resultado

Agora, aperte F5 para iniciar a depuração do projeto. Selecione um emulador existente ou crie um novo se for necessário.

Se seu celular estiver plugado no computador e com o modo desenvolver ativado, você poderá rodar o aplicativo direto no celular.

Conseguiu chegar até aqui? Parabéns, você acaba de criar um aplicativo que consome uma API de filmes. Agora você acaba de liberar uma nova conquista!

O código completo pode ser baixado aqui.

Espero que tenham gostado, deixem seus comentários e um forte abraço!

Desafios

  1. Adicionar um ícone e uma tela de splash para o aplicativo;
  2. Na MovieDetailPage adicionar pelo menos 2 novas informações;
  3. Criar um IconButton na AppBar que altere o crossAxisCount do GridView entre 2 e 3. Não se esqueçam do setState;
  4. Trocar a lógica do ScrollController por InfiniteScrollPagination;
  5. Utilizar FancyShimmerImage para substituir o NetworkImage do poster (MoviePage) e banner (MovieDetailPage);

Lista de APIs

Brinque com outras APIs

Continue estudando

Leitura recomendada

--

--

Kleber Andrade
Flutter — Comunidade BR

Expert Developer of Robot, Games, Artificial Intelligence. Languages C/C++, Python, Java and C#