Busque dados da internet
Refatore seu aplicativo para usar um cliente de API robusto e pronto para produção no CLI da Wikipedia.
No Capítulo 3, você usou o pacote http para fazer uma requisição simples.
Agora, você vai revisitar o HTTP para
construir um cliente de API robusto e pronto para produção dentro do pacote wikipedia.
Você vai aprender como lidar com parâmetros de consulta,
mapear respostas JSON para seus modelos de dados e
exportar essas funções para uso na sua CLI.
O que você vai realizar
Pré-requisitos
#Antes de começar este capítulo, certifique-se de:
-
Ter concluído o Capítulo 11 e ter um
ambiente de desenvolvimento Dart funcionando com o projeto
dartpedia. - Entender conceitos básicos de redes (como APIs e requisições HTTP).
- Entender formatos básicos de serialização de dados, como JSON.
Tarefas
#
Neste capítulo, você vai deixar de lado os scripts simples e
implementar uma camada de API adequada.
Você vai trabalhar dentro do pacote wikipedia para
implementar a lógica do cliente de API, o que
melhora a escalabilidade e a manutenibilidade do seu aplicativo.
Tarefa 1: Adicione a dependência http ao pacote wikipedia
#
Para fazer requisições HTTP, você precisa
adicionar o pacote http como dependência do pacote wikipedia.
Abra o arquivo
wikipedia/pubspec.yamlno seu projeto.Localize a seção
dependencies.-
Adicione
http: ^1.3.0(ou a versão estável mais recente) emdependencies.wikipedia/pubspec.yamlyamldependencies: http: ^1.3.0 Salve o arquivo
pubspec.yaml.Execute
dart pub getno terminal, a partir do diretóriowikipedia.
Tarefa 2: Implemente as chamadas à API da Wikipedia
#Em seguida, você vai criar as funções de API para buscar dados da Wikipedia. Você vai criar três arquivos:
-
summary.dart: este arquivo vai conter funções para recuperar resumos de artigos. -
search.dart: este arquivo vai tratar as consultas de busca para encontrar artigos. -
get_article.dart: este arquivo vai conter funções para buscar o conteúdo completo de um artigo.
Crie o diretório
wikipedia/lib/src/api.Crie o arquivo
wikipedia/lib/src/api/summary.dart.-
Adicione o seguinte código em
wikipedia/lib/src/api/summary.dart:wikipedia/lib/src/api/summary.dartdartimport 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import '../model/summary.dart'; Future<Summary> getRandomArticleSummary() async { final http.Client client = http.Client(); try { final Uri url = Uri.https( 'en.wikipedia.org', '/api/rest_v1/page/random/summary', ); final http.Response response = await client.get(url); if (response.statusCode == 200) { final Map<String, Object?> jsonData = jsonDecode(response.body) as Map<String, Object?>; return Summary.fromJson(jsonData); } else { throw HttpException( '[WikipediaApiClient.getRandomArticleSummary] ' 'statusCode=${response.statusCode}, body=${response.body}', ); } } on FormatException { // todo: log exceptions rethrow; } finally { client.close(); } } Future<Summary> getArticleSummaryByTitle(String articleTitle) async { final http.Client client = http.Client(); try { final Uri url = Uri.https( 'en.wikipedia.org', '/api/rest_v1/page/summary/$articleTitle', ); final http.Response response = await client.get(url); if (response.statusCode == 200) { final Map<String, Object?> jsonData = jsonDecode(response.body) as Map<String, Object?>; return Summary.fromJson(jsonData); } else { throw HttpException( '[WikipediaApiClient.getArticleSummaryByTitle] ' 'statusCode=${response.statusCode}, body=${response.body}', ); } } on FormatException { // todo: log exceptions rethrow; } finally { client.close(); } }Este código define duas funções:
getRandomArticleSummaryegetArticleSummaryByTitle. Ambas usam o pacotehttppara fazer requisições GET à API da Wikipedia e retornar um objetoSummary.getRandomArticleSummarybusca o resumo de um artigo aleatório, enquantogetArticleSummaryByTitlebusca o resumo de um título de artigo específico. Em seguida, crie o arquivo
wikipedia/lib/src/api/search.dart.-
Adicione o seguinte código em
wikipedia/lib/src/api/search.dart:wikipedia/lib/src/api/search.dartdart import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import '../model/search_results.dart'; Future<SearchResults> search(String searchTerm) async { final http.Client client = http.Client(); try { final Uri url = Uri.https( 'en.wikipedia.org', '/w/api.php', <String, Object?>{ 'action': 'opensearch', 'format': 'json', 'search': searchTerm, }, ); final http.Response response = await client.get(url); if (response.statusCode == 200) { final List<Object?> jsonData = jsonDecode(response.body) as List<Object?>; return SearchResults.fromJson(jsonData); } else { throw HttpException( '[WikipediaApiClient.search] ' 'statusCode=${response.statusCode}, ' 'body=${response.body}', ); } } on FormatException { rethrow; } finally { client.close(); } }Este código define a função
search, que usa o pacotehttppara fazer uma requisição GET ao endpointopensearchda API da Wikipedia e retorna um objetoSearchResults. O endpointopensearché usado para buscar artigos da Wikipedia com base em um termo de busca. Crie o arquivo
wikipedia/lib/src/api/get_article.dart.-
Adicione o seguinte código em
wikipedia/lib/src/api/get_article.dart:wikipedia/lib/src/api/get_article.dartdartimport 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import '../model/article.dart'; Future<List<Article>> getArticleByTitle(String title) async { final http.Client client = http.Client(); try { final Uri url = Uri.https( 'en.wikipedia.org', '/w/api.php', <String, Object?>{ // order matters - explaintext must come after prop 'action': 'query', 'format': 'json', 'titles': title.trim(), 'prop': 'extracts', 'explaintext': '', }, ); final http.Response response = await client.get(url); if (response.statusCode == 200) { final Map<String, Object?> jsonData = jsonDecode(response.body) as Map<String, Object?>; return Article.listFromJson(jsonData); } else { throw HttpException( '[WikipediaApiClient.getArticleByTitle] ' 'statusCode=${response.statusCode}, ' 'body=${response.body}', ); } } on FormatException { // TODO: log rethrow; } finally { client.close(); } }Este código define a função
getArticleByTitle, que usa o pacotehttppara fazer uma requisição GET à API da Wikipedia e retorna um objetoList<Article>. Essa função recupera o conteúdo de um artigo da Wikipedia com base no seu título.
Tarefa 3: Exporte as funções de API
#
Agora que você criou as funções de API,
precisa exportá-las da biblioteca wikipedia para que
possam ser usadas pelo pacote cli.
Você também vai exportar os modelos existentes.
Abra o arquivo
wikipedia/lib/wikipedia.dart.-
Adicione as seguintes declarações
exportao arquivo:wikipedia/lib/wikipedia.dartdartexport 'src/api/get_article.dart'; export 'src/api/search.dart'; export 'src/api/summary.dart'; export 'src/model/article.dart'; export 'src/model/search_results.dart'; export 'src/model/summary.dart'; export 'src/model/title_set.dart';Essas declarações
exporttornam as funções de API e os modelos disponíveis para outros pacotes que dependem do pacotewikipedia.
Tarefa 4: Verifique com testes
#
Agora que você implementou as funções de API e atualizou as
dependências do pacote, é uma boa prática executar os testes que você criou no capítulo
anterior. Isso confirma que suas mudanças não quebraram a funcionalidade
existente do pacote wikipedia.
Abra o terminal e navegue até o diretório
wikipedia/test.-
Remova o arquivo de teste padrão executando o comando
rm wikipedia_test.dart(no macOS ou Linux) oudel wikipedia_test.dart(no Windows). Esse arquivo foi gerado automaticamente, mas não é usado no nosso projeto. Abra o terminal e navegue até o diretório
wikipedia.-
Execute o comando
dart test.Você deve ver uma saída parecida com esta, confirmando que todos os seus testes existentes continuam passando:
bash00:02 +3: All tests passed! This confirms that the wikipedia package is still working as expected.
Revisão
#O que você realizou
Veja um resumo do que você construiu e aprendeu nesta lição.Construiu URIs complexas com parâmetros de consulta
Você usou Uri.https() com um mapa de parâmetros de consulta para montar as URLs da API. Essa abordagem codifica corretamente os caracteres especiais e lida com combinações complexas de parâmetros.
Criou um cliente de API pronto para produção
Você implementou várias funções que gerenciam corretamente o ciclo de vida do cliente HTTP com try
e finally, e mapeia as respostas JSON brutas para objetos Dart tipados.
Exportou funções e tipos para reutilização
Você adicionou declarações export em wikipedia.dart para expor tanto as funções de API quanto os tipos de modelo de dados. Isso cria uma biblioteca pública que o seu pacote
cli pode importar e usar diretamente.
Quiz
#Confira seu entendimento
1 / 3Uri.https?
-
Passe-os como um terceiro argumento, um map:
Uri.https('api.com', '/search', {'q': 'dart'})Isso mesmo!
O terceiro parâmetro aceita um
Map<String, dynamic>com os parâmetros de consulta. O Dart faz a codificação da URL automaticamente. -
Acrescente-os à string do caminho:
Uri.https('api.com', '/search?q=dart')Não exatamente.
Parâmetros de consulta na string do caminho funcionam, mas não são a abordagem mais limpa.
-
Use concatenação de strings:
Uri.https('api.com', '/search') + '?q=dart'Não exatamente.
Não é possível concatenar strings a objetos
Uricom+.Urioferece outro mecanismo para adicionar parâmetros de consulta. -
Chame
.addQueryParam('q', 'dart')no objetoUri.Não exatamente.
Objetos
Urisão imutáveis e não têm um métodoaddQueryParam. Os parâmetros de consulta devem ser especificados de outra forma.
client.get(url), como você deve verificar se a requisição foi bem-sucedida?
-
Verificar se
response.statusCode == 200(ou outro código de sucesso).Isso mesmo!
Os códigos de status HTTP indicam sucesso (200-299) ou diversas falhas (400 e 500). Sempre verifique antes de processar o corpo da resposta.
-
Verificar se
response.bodynão está vazio.Não exatamente.
Um corpo vazio pode ser válido (como um 204 No Content). O conteúdo do corpo, por si só, não diz se a requisição deu certo.
-
Envolver a chamada em try/catch, já que requisições bem-sucedidas não lançam exceções.
Não exatamente.
Erros HTTP (como 404 e 500) não lançam exceções por padrão. A requisição termina normalmente mesmo quando o servidor retorna um erro.
-
Verificar se
response.isSuccessretorna true.Não exatamente.
Não existe uma propriedade
isSuccessemResponse. Você precisa consultar outra propriedade do objeto de resposta.
finally para chamar client.close(). Por que isso é importante?
-
Para garantir que os recursos de rede sejam liberados mesmo se ocorrer uma exceção.
Isso mesmo!
O
finallyroda tanto se o bloco try for bem-sucedido quanto se lançar uma exceção. Isso garante que as conexões do client sejam fechadas corretamente, evitando vazamento de recursos. -
Para salvar os dados da resposta em disco antes de a função retornar.
Não exatamente.
close()não salva dados em lugar nenhum. Salvar dados exigiria operações explícitas com arquivos. -
Para enviar uma mensagem de 'conexão fechada' ao servidor.
Não exatamente.
Embora fechar afete a conexão, o principal objetivo é a limpeza do lado do cliente, não a comunicação com o servidor.
-
Para limpar a resposta da memória e acionar o garbage collector.
Não exatamente.
O garbage collector do Dart cuida da memória automaticamente.
close()libera outro tipo de recurso.
Próxima lição
#
Na próxima lição, você vai concluir sua CLI integrando os comandos do pacote wikipedia
com o pacote cli e adicionando logging para depuração e monitoramento de erros.
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ê.