Obtener datos de internet
Refactoriza tu aplicación para usar un cliente de API robusto y listo para producción para la CLI de Wikipedia.
En el Capítulo 3, usaste el paquete http para hacer una solicitud simple.
Ahora, volverás a visitar HTTP para
construir un cliente de API robusto y listo para producción dentro del paquete wikipedia.
Aprenderás a manejar parámetros de consulta (query parameters),
mapear respuestas JSON a tus modelos de datos y
exportar estas funciones para usarlas en tu CLI.
Qué lograrás
Prerrequisitos
#Antes de comenzar este capítulo, asegúrate de:
- Haber completado el Capítulo 10 y tener un
entorno de desarrollo de Dart en funcionamiento con el proyecto
dartpedia. - Entender conceptos básicos de redes (como APIs y solicitudes HTTP).
- Entender formatos básicos de serialización de datos como JSON.
Tareas
#En este capítulo, irás más allá de los simples scripts e
implementarás una capa de API adecuada.
Trabajarás dentro del paquete wikipedia para
implementar la lógica del cliente de API, lo que
mejora la escalabilidad y mantenibilidad de tu aplicación.
Tarea 1: Agregar la dependencia http al paquete wikipedia
#Para realizar solicitudes HTTP, necesitas
agregar el paquete http como una dependencia al paquete wikipedia.
Abre el archivo
wikipedia/pubspec.yamldentro de tu proyecto.Localiza la sección
dependencies.-
Agrega
http: ^1.3.0(o la última versión estable) bajodependencies.yamldependencies: http: ^1.3.0 Guarda el archivo
pubspec.yaml.Ejecuta
dart pub geten tu terminal desde el directoriowikipedia.
Tarea 2: Implementar las llamadas a la API de Wikipedia
#A continuación, crearás las funciones de la API para obtener datos de Wikipedia. Crearás tres archivos:
summary.dart: Este archivo contendrá funciones para recuperar resúmenes de artículos.search.dart: Este archivo manejará las consultas de búsqueda para encontrar artículos.get_article.dart: Este archivo contendrá funciones para obtener el contenido completo de un artículo.
Crea el directorio
wikipedia/lib/src/api.Crea el archivo
wikipedia/lib/src/api/summary.dart.-
Agrega el siguiente código a
wikipedia/lib/src/api/summary.dart:dartimport '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 dos funciones:
getRandomArticleSummaryygetArticleSummaryByTitle. Ambas funciones usan el paquetehttppara realizar solicitudes GET a la API de Wikipedia y devuelven un objetoSummary.getRandomArticleSummaryobtiene un resumen de un artículo aleatorio, mientras quegetArticleSummaryByTitleobtiene un resumen para el título de un artículo específico. A continuación, crea el archivo
wikipedia/lib/src/api/search.dart.-
Agrega el siguiente código a
wikipedia/lib/src/api/search.dart:dart 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 la función
search, que utiliza el paquetehttppara realizar una solicitud GET al endpointopensearchde la API de Wikipedia y devuelve un objetoSearchResults. El endpointopensearchse utiliza para buscar artículos de Wikipedia basados en un término de búsqueda. Crea el archivo
wikipedia/lib/src/api/get_article.dart.-
Agrega el siguiente código a
wikipedia/lib/src/api/get_article.dart:dartimport '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 la función
getArticleByTitle, que utiliza el paquetehttppara realizar una solicitud GET a la API de Wikipedia y devuelve un objetoList<Article>. Esta función recupera el contenido de un artículo de Wikipedia basándose en su título.
Tarea 3: Exportar las funciones de la API
#Ahora que has creado las funciones de la API,
necesitas exportarlas desde la librería wikipedia para que
puedan ser utilizadas por el paquete cli.
También exportarás los modelos existentes.
Abre el archivo
wikipedia/lib/wikipedia.dart.-
Agrega las siguientes sentencias
exportal archivo:dartexport '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';Estas sentencias
exporthacen que las funciones y modelos de la API estén disponibles para otros paquetes que dependan del paquetewikipedia.
Tarea 4: Verificar con pruebas
#Ahora que has implementado las funciones de la API y
actualizado las dependencias del paquete, es una buena práctica
ejecutar las pruebas que creaste en el capítulo anterior.
Esto confirmará que tus cambios no han
roto la funcionalidad existente del paquete wikipedia.
Abre tu terminal y navega al directorio
wikipedia/test.-
Elimina el archivo de prueba predeterminado ejecutando el comando
rm wikipedia_test.dart(en macOS o Linux) odel wikipedia_test.dart(en Windows). Este archivo se generó automáticamente pero no se utiliza en nuestro proyecto. Abre tu terminal y navega al directorio
wikipedia.-
Ejecuta el comando
dart test.Deberías ver una salida similar a esta, confirmando que todas tus pruebas existentes aún pasan:
bash00:02 +3: All tests passed! This confirms that the wikipedia package is still working as expected.
Revisión
#Qué lograste
Aquí tienes un resumen de lo que construiste y aprendiste en esta lección.Construiste URIs complejas con parámetros de consulta (query parameters)
Usaste Uri.https() con un mapa de parámetros de consulta para construir URLs de API. Este enfoque codifica adecuadamente los caracteres especiales y maneja combinaciones complejas de parámetros de consulta.
Creaste un cliente de API listo para producción
Implementaste una variedad de funciones que gestionan adecuadamente el ciclo de vida del cliente HTTP con try
y finally, y mapean las respuestas JSON crudas a objetos Dart tipados.
Exported functions and types for reuse
Añadiste sentencias de exportación en wikipedia.dart para exponer tanto las funciones de la API como los tipos de modelos de datos. Esto crea una librería pública que tu
cli paquete puede importar y usar directamente.
Cuestionario
#Pon a prueba tu comprensión
1 / 3Uri.https?Llamar a
.addQueryParam('q', 'dart')en el objetoUri.No exactamente.
Los objetos
Urison inmutables y no tienen un métodoaddQueryParam. Los parámetros de consulta deben especificarse de manera diferente.Usar concatenación de cadenas:
Uri.https('api.com', '/search') + '?q=dart'No exactamente.
No puedes concatenar cadenas a objetos
Uriusando+.Uriproporciona un mecanismo diferente para agregar parámetros de consulta.Pasarlos como un mapa en el tercer argumento:
Uri.https('api.com', '/search', {'q': 'dart'})¡Correcto!
El tercer parámetro acepta un
Map<String, dynamic>de parámetros de consulta. Dart maneja la codificación URL automáticamente.Añadirlos a la cadena de la ruta:
Uri.https('api.com', '/search?q=dart')No exactamente.
Los parámetros de consulta (query parameters) en la cadena de la ruta funcionan, pero no son el enfoque más limpio.
client.get(url), how should you check if the request was successful?Envolver la llamada en try/catch, ya que las solicitudes exitosas no lanzan excepciones.
No exactamente.
Los errores HTTP (como 404 y 500) no lanzan excepciones de forma predeterminada. La solicitud se completa normalmente incluso cuando el servidor devuelve un error.
Verificar si
response.bodyno está vacío.No exactamente.
Un cuerpo vacío podría ser válido (como un 204 No Content). El contenido del cuerpo por sí solo no te indica si la solicitud tuvo éxito.
Verificar si
response.statusCode == 200(u otro código de éxito).¡Correcto!
Los códigos de estado HTTP indican éxito (200-299) o varios fallos (400s, 500s). Siempre verifícalos antes de procesar el cuerpo de la respuesta.
Verificar si
response.isSuccessdevuelve true.No exactamente.
No hay una propiedad
isSuccessenResponse. Necesitas examinar una propiedad diferente del objeto de respuesta.
finally block to call client.close(). Why is this important?Para enviar un mensaje de 'conexión cerrada' al servidor.
No exactamente.
Aunque cerrar afecta a la conexión, el propósito principal es la limpieza del lado del cliente, not comunicarse con el servidor.
Para guardar los datos de la respuesta en el disco antes de que la función retorne.
No exactamente.
close()no guarda datos en ningún lado. Guardar datos requeriría operaciones explícitas sobre archivos.Para garantizar que los recursos de red se liberen incluso si ocurre una excepción.
¡Correcto!
finallyse ejecuta tanto si el bloque try tiene éxito como si lanza una excepción. Esto asegura que las conexiones del cliente se cierren adecuadamente, evitando fugas de recursos.Para limpiar la respuesta de la memoria y activar el recolector de basura (garbage collector).
No exactamente.
El recolector de basura de Dart gestiona la memoria automáticamente.
close()libera un tipo diferente de recurso.
Siguiente lección
#En la siguiente lección, completarás la CLI
integrando el paquete wikipedia con el paquete cli.
Implementarás la lógica de comandos y mostrarás los resultados al usuario.
A menos que se indique lo contrario, la documentación de este sitio refleja Dart 3.12.2. Página actualizada por última vez el 17-06-2026. Ver fuente oreportar un problema.