Como obter dados da internet no Flutter usando HTTP
17 min17 minutos de leitura
17 min17 minutos de leitura
Autor(a)
Jhoisnáyra Vitória Rodrigues de Almeida
Scuba Team Mobile (com foco em Flutter). Estudante de Ciência da Computação na UFPI, pesquisadora da área de Internet das Coisas e formada em Eletrônica pelo IFPI.
Inscreva-se em nossa Newsletter
Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.
Quando trabalhamos com desenvolvimento front-end (parte da aplicação com a qual o usuário interage e vê - em geral é a tela), seja ele mobile ou web, é comum que precisemos nos comunicar com o back-end (de onde vêm os dados, o que torna a aplicação funcional de fato - em geral, um banco de dados), e uma das primeiras comunicações que aprendemos é a obtenção de dados da internet.
Neste artigo, vamos aprender como obter dados da internet no Flutter utilizando a biblioteca HTTP, entendendo da requisição para a internet até a aplicação final exibindo os dados na tela para o usuário.
E o melhor de tudo: vamos aprender tudo isso na prática - com um projeto real! Essa aplicação obtém, da internet, uma lista de filmes (com título e imagem) e a mostra para o usuário. Veja:
Conhecimentos prévios
Para que aproveite bem o conteúdo deste artigo, é interessante que você domine algumas habilidades e técnicas em Flutter (aliás, temos cursos que ensinam esses conhecimentos aqui na Alura):
Entendendo nosso projeto: O aplicativo Filmes Studio Ghibli
Vamos utilizar um projeto prático para aprender a habilidade de obter dados da internet e mostrá-los em um aplicativo Flutter! Você pode acessar o projeto inicial neste link do GitHub.
Imagine que você precisa fazer um projeto de aplicativo Flutter com as seguintes características:
A pessoa usuária consegue ver uma lista de filmes do Studio Ghibli;
Essa lista é um tipo de dado disponível apenas de forma online, ou seja, o celular e o app precisam se conectar à internet e pegar esses dados para depois exibi-los na tela para a pessoa usuária.
Como podemos, então, fazer com que o app acesse esses dados disponíveis na internet (mais especificamente em um banco de dados)?
Bom, precisamos seguir uma série de passos:
Instalar o pacote HTTP;
Usar o pacote HTTP para fazer uma requisição GET que obtém os dados dos filmes (disponíveis na internet);
Converter os dados obtidos do tipo “JSON” em objetos;
Mostrar os dados dos filmes.
Veremos cada um dessas etapas! A primeira envolve um tal de pacote HTTP - mas o que é isso?
Conhecendo o pacote HTTP
Para obter dados da internet (no nosso caso, informações sobre filmes do estúdio Ghibli), precisamos de um pacote HTTP que vai fazer a comunicação com a internet. Vamos ver isso com mais detalhes!
Em sua documentação, o Flutter oferece o pacote HTTP, que faz requisições HTTP que são mensagens enviadas do cliente para um servidor - o cliente pode ser um app, por exemplo.
Ou seja, a função do pacote HTTP é enviar “mensagens” para a internet e pedir os dados para um servidor. O nome técnico dessas mensagens/pedidos é requisições HTTP.
Sobre as requisições HTTP, essas mensagens enviadas para o servidor podem ser de vários tipos ou verbos, sendo os mais conhecidos:
GET: Usado para obter dados da internet (que podem ser mostrados na tela depois);
POST: Usado para enviar dados novos (para salvar uma informação, por exemplo);
PUT: Usado para substituir dados já existentes (que edita um dado já existente); e
DELETE: Usado para apagar dados.
Além disso, quando enviamos uma requisição (request, em inglês) ao servidor, vamos receber de volta uma resposta (response), e essa resposta pode conter o que esperávamos receber de volta ou, por exemplo, a informação de algum erro ocorrido.
Em geral, junto da resposta do servidor, vem um código chamado Status Code, e ele pode ser de diferentes valores:
Respostas informativas (100 a 199);
Respostas bem-sucedidas (200 a 299);
Mensagens de redirecionamento (300 a 399);
Respostas de erro do cliente (400 a 499);
Respostas de erro do servidor (500 a 599).
Quando obtemos sucesso na requisição (recebemos o que esperávamos), o valor do Status Code é 200!
Em Flutter, e com o pacote HTTP, não é diferente! Nós enviamos uma request e recebemos uma response.
E agora que você já sabe o que é o pacote HTTP, pode começar a praticar. Vamos lá?
Passo 1: Instalando o pacote
Para instalar o pacote HTTP em nosso projeto, vamos usar o seguinte comando no terminal:
flutter pub add http
Isso deve adicionar a seguinte linha no seu arquivo pubspec.yaml:
dependencies:HTTP:^0.13.5
A versão utilizada durante a produção deste artigo é a ^0.13.5, mas pode ser que quando esteja lendo, já se tenha uma versão mais atualizada (mas para que funcione bem, exatamente como explico no artigo, é importante usar a mesma versão que utilizei). E se tiver interesse em conhecer mais sobre a biblioteca, acesse o site oficial.
Pronto, tudo instalado, e agora podemos pôr a mão no código!
Passo 2: Obtendo dados da Web com GET
Para começar a implementar a funcionalidade na nossa aplicação Filmes Studio Ghibli, vamos precisar da lista de filmes (dados que estão disponíveis apenas na internet).
Aprendemos que, para obter esses dados da internet em um projeto Flutter, precisamos de um pacote como o HTTP que se comunica com a internet e permite que a gente use um verbo do tipo GET que vai fazer uma solicitação a uma API (veremos o que é isso já já).
Em resumo, quando pegamos um dado da internet, o app se comunica com uma API (e não com o servidor/banco de dados diretamente).
Uma API, de maneira bem simples, pode ser vista como um meio de comunicação e integração entre o front-end e o back-end, como um telefone entre eles!
No caso, vamos simular uma API com um arquivo hospedado no GitHub com uma lista de filmes que queremos exibir. Usaremos, então, uma Fake API que contém os dados dos filmes que queremos exibir.
Faz sentido?
A seguir, precisamos acessar essa API simulada. Para fazer isso, em nosso projeto, vamos criar um arquivo com uma função chamada getFilmes. Essa função vai fazer uma requisição GET, ou seja, um pedido dos dados (como se o app dissesse para a API “Oi, me vê os dados aí, por favor!”).
Com apenas uma função, fazemos a requisição GET para obter os dados! Veja uma representação desse processo:
Como vemos na imagem, o dispositivo com o projeto Flutter, graças ao pacote HTTP, faz uma requisição GET - no caso, a função getFilmes.
Vamos entender os detalhes da implementação dessa função:
Para começar, importamos o pacote http:
import'package:http/http.dart'as http;
Depois, veja que adotamos uma função assíncrona - visto que estamos lidando com informações da internet e esses dados podem demorar para chegar - e sem retorno - pois, por enquanto, queremos apenas imprimir a resposta no terminal. Daí a necessidade de usar as palavras Future<void>, async e await;
Como a requisição nos retorna uma resposta, um valor, criamos uma variável chamada response, que irá guardar esse resultado recebido; e
Na requisição, usamos http.get(), cujo conteúdo dentro desse comando é exatamente um URI (identificador de recurso), daí a necessidade transformarmos o nosso link nisso, com a instrução uri.parse.
Assim, a requisição é enviada para a API (que faz a ligação entre o dispositivo/aplicativo e o servidor). Por sua vez, a API pede os dados para o servidor:
Em seguida, o banco responde a API:
Por último, a API faz a resposta para o dispositivo, enviando o dado recebido em formato JSON:
Ufa! Finalmente! E o resultado da nossa requisição GET é a seguinte lista, em formato JSON, com nomes e imagens de filmes:
Você pode estar se perguntando o tipo de informação que recebemos da API simulada e o conteúdo exato dela, pois falamos de um tal de JSON. Vamos entender tudo isso!
Como dito anteriormente, estamos usando um arquivo no GitHub (para simular uma API), que está em um formato específico, bastante utilizado na internet quando trabalhamos com APIs: o JSON.
O JSON é um formato leve, utilizado na internet para troca de dados entre diferentes sistemas. No Flutter, vamos precisar converter esses dados em objetos para que possamos exibir em nossa aplicação.
Passo 3: Convertendo dados em objetos
Ao recebermos dados em formato de JSON, é necessário convertê-los em um model (já veremos o que é isso com detalhes), ou seja, um modelo de representação desses dados. Em nosso código, estamos recebendo filmes com nomes e imagens, e podemos criar o seguinte model:
Este model nada mais é do que uma classe Filme, com os atributos recebidos no JSON (nome e imagem), e estamos usando dois construtores:
Um construtor comum que recebe duas Strings (nome e imagem); e
Um construtor nomeado e de redirecionamento, chamado fromJson (“do json”, em português) que recebe um Map chamado json - é esse construtor de redirecionamento que vai fazer a conversão dos dados do tipo JSON (que obtivemos da internet) para um objeto no Flutter.
Agora que temos o model e o construtor que vai realizar a conversão (pense como uma “tradução” de um tipo de dado para outro), precisamos aplicar o model que criamos.
Vamos lá?
Aplicando o model que criamos
Para converter o arquivo JSON que recebemos em uma lista de objetos do tipo Filme, faremos da seguinte forma no arquivo repository.dart:
Agora, invés de usar um Future<void> (sem retornar nada), vamos ter uma função Future<List<Filme>>, pois vamos retornar uma lista de objetos do tipo Filme:
Future<List<Filme>> getFilmes() async {
//…
}
Guardamos, em uma variável chamada json, a conversão do JSON em um objeto:
final json = jsonDecode(response.body);
Retornamos uma lista (List) com objetos do tipo Filme, realizando um map de cada elemento do objeto JSON, transformando um a um em objetos Filme:
Legal! Agora que concluímos nossa função getFilmes, podemos utilizá-la para exibir o resultado para o usuário. Ou seja, o app já converte o JSON recebido da internet em uma lista de objetos do tipo Filme.
Tratando exceções na aplicação
Se você tiver testado o código anterior, pode ter percebido que, caso o link esteja incorreto, teremos uma exceção, ou seja, um erro que ocorreu enquanto o aplicativo estava executando.
Essa exceção acontece pois há um erro na requisição que fizemos e não recebemos nenhum dado, portanto, precisamos tratá-la de alguma forma, e é isso que vamos fazer!
Para tratar, precisamos utilizar um condicional if-else que verifique se a requisição ocorreu com sucesso ou não. Podemos usar o response.statusCode neste caso, pois o valor dele vai indicar sucesso (se for 200) e algo diferente (se for um valor diferente de 200). Veja:
E implementando essa verificação no nosso código, ficaria da seguinte maneira:
import'package:http/http.dart'as http;
import'dart:convert';
import'../models/filme.dart';
Future<List<Filme>> getFilmes() async {
final response = await http.get(Uri.parse(
'https://raw.githubusercontent.com/alura-cursos/obtendo_dados_com_flutter_http/main/filmes.json'));
if (response.statusCode == 200) {
final json = jsonDecode(response.body);
return List<Filme>.from(json.map((elemento) {
return Filme.fromJson(elemento);
}));
} else {
return Future.error("Ops! Um erro ocorreu.");
}
}
Em que:
Verificamos se ocorreu tudo certo (se response.statusCode é igual a 200); e
Caso tenha ocorrido tudo certo, retornamos a lista de filmes, como vimos anteriormente;
Caso algo de errado tenha acontecido e não tenhamos dados, retornamos um objeto Future com um erro e a seguinte mensagem: “Ops! Um erro ocorreu”.
Tudo certo! Conseguimos colocar, dentro do dispositivo, os dados dos filmes do Studio Ghibli e cuidamos para que nenhuma exceção prejudique seu funcionamento. Bora mostrá-los na tela?
Passo 4: Exibindo resultados na tela
Para exibir os filmes na tela, vamos criar um novo arquivo chamado home.dart, no qual vamos criar um Widget do tipo Stateful chamado Home, ou seja, um Widget mutável, que possui estado.
Estamos criando uma lista de filmes chamada futureFilmes, e ela é nullable, pois começa sem um valor;
Future<List<Filme>>? futureFilmes;
O initState é um método de Widgets Stateful que é chamado quando iniciamos uma tela, e estamos inicializando dentro dele a lista futureFilmes, usando a nossa função getFilmes:
Temos uma lista de objetos do tipo Filme, a futureFilmes, podemos agora utilizá-la e mostrar ao usuário o resultado na tela. Assim, usaremos o FutureBuilder, uma classe de Widget que utiliza o resultado de um Future para construir a si mesmo:
Perfeito! Agora temos a nossa aplicação final, recebendo dados da internet, convertendo-os e mostrando para o usuário. Abaixo você pode conferir o resultado final que obtemos:
Concluímos nossa tarefa! Agora, se tiver curiosidade, você pode entender melhor como o projeto Filmes Studio Ghibli está organizado!
Estrutura do projeto e Widgets criados
Vamos ver a árvore de widgets do nosso projeto completo? Como você pode ver, utilizamos outros Widgets:
Na imagem acima, vemos a árvore do aplicativo, em que podemos observar que temos um Scaffold que contém um FutureBuilder, que, por sua vez, exibe um Widget chamado ListaFilmes (criado por mim). O ListaFilmes contém um GridView que mostra uma lista de WidgetsCardFilme (também criado por mim). Repare que, a partir do CardFilme, a estrutura da árvore se repete, pois se trata de uma lista que repete o mesmo widget de cartão que apresenta cada filme.
E, além dos códigos que demonstrei aqui, utilizei de mais dois arquivos, os quais deixo para você - os WidgetsListaFilmes e CardFilme:
Agora você já deve ser capaz de obter dados da internet utilizando o pacote HTTP de Flutter, além de exibi-los para a pessoa usuária da aplicação.
Vimos todo o fluxo de requisição e resposta para obter dados da internet, do dispositivo até o servidor e, também, passando pela API.
No nosso caso, usamos uma API simulada com um arquivo do Github, pois APIs na internet podem variar e mudar ao longo do tempo e, assim, garantimos que você possa praticar as técnicas ensinadas neste artigo sem se preocupar se a API funciona ou foi desativada.
Abaixo, deixamos um infográfico que resume bem todo o processo de requisição e resposta para obter dados da internet: