Buscar dados da internet
Busque dados pela internet usando o pacote http.
A maioria das aplicações requer alguma forma de comunicação ou recuperação de dados da internet. Muitas aplicações fazem isso por meio de requisições HTTP, que são enviadas de um cliente para um servidor para realizar uma ação específica sobre um recurso identificado por uma URI (Uniform Resource Identifier).
Os dados comunicados via HTTP podem, tecnicamente, estar em qualquer formato, mas usar JSON (JavaScript Object Notation) é uma escolha popular, por causa da sua legibilidade para humanos e da independência de linguagem. O Dart SDK e o ecossistema também têm amplo suporte a JSON, com múltiplas opções para atender melhor aos requisitos da sua aplicação.
Neste tutorial,
você vai aprender mais sobre requisições HTTP, URIs e JSON.
Depois, vai aprender como usar o package:http
e o suporte a JSON do Dart na biblioteca dart:convert
para buscar, decodificar e então usar dados em formato JSON
recuperados de um servidor HTTP.
Conceitos de base
#As seções a seguir trazem algum contexto extra e informações sobre as tecnologias e os conceitos usados no tutorial, para facilitar a busca de dados no servidor. Para ir direto ao conteúdo do tutorial, veja Recuperar as dependências necessárias.
JSON
#JSON (JavaScript Object Notation) é um formato de intercâmbio de dados que se tornou onipresente no desenvolvimento de aplicações e na comunicação cliente-servidor. Ele é leve, mas também fácil para humanos lerem e escreverem, por ser baseado em texto. Com JSON, vários tipos de dados e estruturas simples, como listas e maps, podem ser serializados e representados por strings.
A maioria das linguagens tem muitas implementações, e os parsers ficaram extremamente rápidos, então você não precisa se preocupar com interoperabilidade ou desempenho. Para mais informações sobre o formato JSON, veja Introducing JSON. Para aprender mais sobre como trabalhar com JSON em Dart, veja o guia Using JSON.
Requisições HTTP
#
HTTP (Hypertext Transfer Protocol) é um protocolo stateless
projetado para transmitir documentos,
originalmente entre clientes web e servidores web.
Você interagiu com o protocolo para carregar esta página,
já que o seu navegador usa uma requisição HTTP GET
para recuperar o conteúdo de uma página de um servidor web.
Desde a sua criação, o uso do protocolo HTTP e de suas várias versões
se expandiu para aplicações fora da web também,
basicamente em qualquer lugar onde seja necessária a comunicação de um cliente com um servidor.
As requisições HTTP enviadas do cliente para se comunicar com o servidor
são compostas de vários componentes.
Bibliotecas HTTP, como o package:http, permitem que você
especifique os seguintes tipos de informação:
-
Um método HTTP que define a ação desejada,
como
GETpara recuperar dados ouPOSTpara enviar novos dados. - A localização do recurso por meio de uma URI.
- A versão do HTTP em uso.
- Headers que fornecem informações extras ao servidor.
- Um body opcional, para que a requisição possa enviar dados ao servidor, e não apenas recuperá-los.
Para aprender mais sobre o protocolo HTTP, confira An overview of HTTP no MDN Web Docs.
URIs e URLs
#Para fazer uma requisição HTTP, você precisa fornecer uma URI (Uniform Resource Identifier) do recurso. Uma URI é uma string de caracteres que identifica um recurso de forma única. Uma URL (Uniform Resource Locator) é um tipo específico de URI que também informa a localização do recurso. As URLs de recursos na web contêm três informações. Para esta página, a URL é composta por:
- O scheme, que determina o protocolo usado:
https - A autoridade, ou hostname do servidor:
dart.dev - O path do recurso:
/server/fetch-data.html
Existem também outros parâmetros opcionais, que não são usados nesta página:
- Parâmetros para personalizar comportamentos extras:
?key1=value1&key2=value2 -
Uma âncora, que não é enviada ao servidor
e aponta para um local específico dentro do recurso:
#uris
Para aprender mais sobre URLs, veja What is a URL? no MDN Web Docs.
Recuperar as dependências necessárias
#
A biblioteca package:http fornece uma solução multiplataforma
para fazer requisições HTTP componíveis,
com controle detalhado opcional.
Para adicionar uma dependência ao package:http,
execute o seguinte comando dart pub add
a partir da raiz do seu repositório:
dart pub add http
Para usar o package:http no seu código,
importe-o e, opcionalmente, especifique um prefixo de biblioteca:
import 'package:http/http.dart' as http;
Para aprender mais detalhes sobre o package:http,
veja a página dele no site pub.dev
e a sua documentação da API.
Construir uma URL
#Como mencionado anteriormente, para fazer uma requisição HTTP, primeiro você precisa de uma URL que identifique o recurso solicitado ou o endpoint acessado.
Em Dart, as URLs são representadas por objetos Uri.
Existem muitas formas de construir um Uri,
mas, por causa da sua flexibilidade,
analisar uma string com Uri.parse para
criar um é uma solução comum.
O snippet a seguir mostra duas formas
de criar um objeto Uri
apontando para informações mock, em formato JSON,
sobre o package:http hospedadas neste site:
// Parse the entire URI, including the scheme
Uri.parse('https://dart.dev/f/packages/http.json');
// Specifically create a URI with the https scheme
Uri.https('dart.dev', '/f/packages/http.json');
Para aprender outras formas de construir e manipular URIs,
veja a documentação de URI.
Fazer uma requisição de rede
#
Se você só precisa buscar rapidamente uma representação em string
de um recurso solicitado,
pode usar a função de nível superior read
encontrada no package:http,
que retorna um Future<String> ou lança
uma ClientException
se a requisição não tiver sido bem-sucedida.
O exemplo a seguir usa read para
recuperar as informações mock, em formato JSON,
sobre o package:http como uma string,
e então as imprime:
void main() async {
final httpPackageUrl = Uri.https('dart.dev', '/f/packages/http.json');
final httpPackageInfo = await http.read(httpPackageUrl);
print(httpPackageInfo);
}
Isso resulta na seguinte saída em formato JSON,
que também pode ser vista no seu navegador em
/f/packages/http.json.
{
"name": "http",
"latestVersion": "1.1.2",
"description": "A composable, multi-platform, Future-based API for HTTP requests.",
"publisher": "dart.dev",
"repository": "https://github.com/dart-lang/http"
}
Observe a estrutura dos dados (neste caso, um map), já que você vai precisar dela ao decodificar o JSON mais adiante.
Se você precisar de outras informações da resposta,
como o código de status
ou os headers,
pode usar a função de nível superior get,
que retorna um Future com uma Response.
O snippet a seguir usa get para obter a resposta completa,
para sair mais cedo se a requisição não tiver sido bem-sucedida,
o que é indicado por um código de status 200:
void main() async {
final httpPackageUrl = Uri.https('dart.dev', '/f/packages/http.json');
final httpPackageResponse = await http.get(httpPackageUrl);
if (httpPackageResponse.statusCode != 200) {
print('Failed to retrieve the http package!');
return;
}
print(httpPackageResponse.body);
}
Existem muitos outros códigos de status além de 200, e a sua aplicação pode querer tratá-los de forma diferente. Para aprender o que cada código de status significa, veja HTTP response status codes no MDN Web Docs.
Algumas requisições ao servidor exigem mais informações,
como autenticação ou informações de user-agent;
nesse caso, você pode precisar incluir headers HTTP.
Você pode especificar headers passando um Map<String, String>
com os pares chave-valor no parâmetro nomeado opcional headers:
await http.get(
Uri.https('dart.dev', '/f/packages/http.json'),
headers: {'User-Agent': '<product name>/<product-version>'},
);
Fazer múltiplas requisições
#
Se você está fazendo várias requisições ao mesmo servidor,
pode manter uma conexão persistente
por meio de um Client,
que tem métodos semelhantes aos de nível superior.
Só certifique-se de encerrar com
o método close
quando terminar:
void main() async {
final httpPackageUrl = Uri.https('dart.dev', '/f/packages/http.json');
final client = http.Client();
try {
final httpPackageInfo = await client.read(httpPackageUrl);
print(httpPackageInfo);
} finally {
client.close();
}
}
Para que o cliente possa tentar novamente requisições que falharam,
importe package:http/retry.dart e
envolva o Client criado em um RetryClient:
import 'package:http/http.dart' as http;
import 'package:http/retry.dart';
void main() async {
final httpPackageUrl = Uri.https('dart.dev', '/f/packages/http.json');
final client = RetryClient(http.Client());
try {
final httpPackageInfo = await client.read(httpPackageUrl);
print(httpPackageInfo);
} finally {
client.close();
}
}
O RetryClient tem um comportamento padrão para definir quantas
vezes tentar novamente e quanto tempo esperar entre cada requisição,
mas esse comportamento pode ser alterado por parâmetros
dos construtores RetryClient()
ou RetryClient.withDelays().
O package:http tem muito mais funcionalidades e opções de customização,
então confira a página dele no site pub.dev
e a sua documentação da API.
Decodificar os dados recuperados
#Agora que você fez uma requisição de rede e recuperou os dados retornados como string, acessar porções específicas de informação dentro de uma string pode ser um desafio.
Como os dados já estão em formato JSON,
você pode usar a função nativa json.decode
do Dart
da biblioteca dart:convert
para converter a string bruta em
uma representação JSON usando objetos Dart.
Neste caso, os dados JSON são representados em uma estrutura map
e, em JSON, as chaves de um map são sempre strings,
então você pode fazer o cast do resultado de json.decode para Map<String, dynamic>:
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() async {
final httpPackageUrl = Uri.https('dart.dev', '/f/packages/http.json');
final httpPackageInfo = await http.read(httpPackageUrl);
final httpPackageJson = json.decode(httpPackageInfo) as Map<String, dynamic>;
print(httpPackageJson);
}
Criar uma classe estruturada para armazenar os dados
#Para dar mais estrutura ao JSON decodificado, facilitando o trabalho com ele, crie uma classe que possa armazenar os dados recuperados usando tipos específicos, de acordo com o schema dos seus dados.
O snippet a seguir mostra uma representação baseada em classe
que pode armazenar as informações do pacote retornadas
pelo arquivo JSON mock solicitado.
Essa estrutura assume que todos os campos, exceto o repository,
são obrigatórios e sempre fornecidos.
class PackageInfo {
final String name;
final String latestVersion;
final String description;
final String publisher;
final Uri? repository;
PackageInfo({
required this.name,
required this.latestVersion,
required this.description,
required this.publisher,
this.repository,
});
}
Codificar os dados na sua classe
#
Agora que você tem uma classe para armazenar os dados,
precisa adicionar um mecanismo para converter
o JSON decodificado em um objeto PackageInfo.
Converta o JSON decodificado
escrevendo manualmente um método fromJson
que corresponda ao formato JSON anterior,
fazendo o cast dos tipos quando necessário
e tratando o campo opcional repository:
class PackageInfo {
// ···
factory PackageInfo.fromJson(Map<String, dynamic> json) {
final repository = json['repository'] as String?;
return PackageInfo(
name: json['name'] as String,
latestVersion: json['latestVersion'] as String,
description: json['description'] as String,
publisher: json['publisher'] as String,
repository: repository != null ? Uri.tryParse(repository) : null,
);
}
}
Um método escrito à mão, como no exemplo anterior, costuma ser suficiente para estruturas JSON relativamente simples, mas também existem opções mais flexíveis. Para aprender mais sobre serialização e desserialização de JSON, incluindo a geração automática da lógica de conversão, veja o guia Using JSON.
Converter a resposta para um objeto da sua classe estruturada
#Agora você tem uma classe para armazenar os dados e uma forma de converter o objeto JSON decodificado em um objeto desse tipo. Em seguida, você pode escrever uma função que junta tudo:
- Criar a sua
URIa partir de um nome de pacote recebido. - Usar
http.getpara recuperar os dados desse pacote. -
Se a requisição não tiver sido bem-sucedida, lançar uma
Exceptionou, de preferência, uma subclasse deExceptionpersonalizada. -
Se a requisição tiver sido bem-sucedida, usar
json.decodepara decodificar o body da resposta em uma string JSON. -
Converter a string JSON decodificada em um objeto
PackageInfousando o construtor factoryPackageInfo.fromJsonque você criou.
Future<PackageInfo> getPackage(String packageName) async {
final packageUrl = Uri.https('dart.dev', '/f/packages/$packageName.json');
final packageResponse = await http.get(packageUrl);
// If the request didn't succeed, throw an exception
if (packageResponse.statusCode != 200) {
throw PackageRetrievalException(
packageName: packageName,
statusCode: packageResponse.statusCode,
);
}
final packageJson = json.decode(packageResponse.body) as Map<String, dynamic>;
return PackageInfo.fromJson(packageJson);
}
class PackageRetrievalException implements Exception {
final String packageName;
final int? statusCode;
PackageRetrievalException({required this.packageName, this.statusCode});
}
Utilizar os dados convertidos
#Agora que você recuperou os dados e os converteu para um formato mais fácil de acessar, pode usá-los como quiser. Algumas possibilidades incluem exibir informações em um CLI ou mostrá-las em uma aplicação web ou Flutter.
Aqui está um exemplo completo e executável
que solicita, decodifica e então exibe
as informações mock sobre os pacotes http e path:
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() async {
await printPackageInformation('http');
print('');
await printPackageInformation('path');
}
Future<void> printPackageInformation(String packageName) async {
final PackageInfo packageInfo;
try {
packageInfo = await getPackage(packageName);
} on PackageRetrievalException catch (e) {
print(e);
return;
}
print('Information about the $packageName package:');
print('Latest version: ${packageInfo.latestVersion}');
print('Description: ${packageInfo.description}');
print('Publisher: ${packageInfo.publisher}');
final repository = packageInfo.repository;
if (repository != null) {
print('Repository: $repository');
}
}
Future<PackageInfo> getPackage(String packageName) async {
final packageUrl = Uri.https('dart.dev', '/f/packages/$packageName.json');
final packageResponse = await http.get(packageUrl);
// If the request didn't succeed, throw an exception
if (packageResponse.statusCode != 200) {
throw PackageRetrievalException(
packageName: packageName,
statusCode: packageResponse.statusCode,
);
}
final packageJson = json.decode(packageResponse.body) as Map<String, dynamic>;
return PackageInfo.fromJson(packageJson);
}
class PackageInfo {
final String name;
final String latestVersion;
final String description;
final String publisher;
final Uri? repository;
PackageInfo({
required this.name,
required this.latestVersion,
required this.description,
required this.publisher,
this.repository,
});
factory PackageInfo.fromJson(Map<String, dynamic> json) {
final repository = json['repository'] as String?;
return PackageInfo(
name: json['name'] as String,
latestVersion: json['latestVersion'] as String,
description: json['description'] as String,
publisher: json['publisher'] as String,
repository: repository != null ? Uri.tryParse(repository) : null,
);
}
}
class PackageRetrievalException implements Exception {
final String packageName;
final int? statusCode;
PackageRetrievalException({required this.packageName, this.statusCode});
@override
String toString() {
final buf = StringBuffer();
buf.write('Failed to retrieve package:$packageName information');
if (statusCode != null) {
buf.write(' with a status code of $statusCode');
}
buf.write('!');
return buf.toString();
}
}
E agora?
#Agora que você recuperou, analisou e usou dados da internet, considere aprender mais sobre Concorrência em Dart. Se os seus dados forem grandes e complexos, você pode mover a recuperação e a decodificação para outro isolate como um worker em segundo plano, evitando que a sua interface fique sem resposta.
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Página atualizada pela última vez em 2026-11-12. Ver código-fonte ou relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.