En este tema, aprenderás cómo integrar GraphQL en tu aplicación Flutter para realizar consultas y mutaciones de datos. GraphQL es un lenguaje de consulta para APIs que permite a los clientes solicitar exactamente los datos que necesitan, lo que puede mejorar la eficiencia y la flexibilidad de las aplicaciones.
Objetivos de Aprendizaje
- Comprender los conceptos básicos de GraphQL.
- Configurar un cliente GraphQL en Flutter.
- Realizar consultas y mutaciones utilizando GraphQL.
- Manejar errores y respuestas de GraphQL.
Conceptos Básicos de GraphQL
¿Qué es GraphQL?
GraphQL es un lenguaje de consulta para APIs y un entorno de ejecución para realizar esas consultas con tus datos existentes. Fue desarrollado por Facebook y ofrece una alternativa a las APIs REST tradicionales.
Ventajas de GraphQL
- Solicitudes específicas: Los clientes pueden solicitar exactamente los datos que necesitan.
- Menos solicitudes: Permite obtener múltiples recursos en una sola solicitud.
- Evolución de la API: Facilita la evolución de la API sin afectar a los clientes existentes.
Componentes de GraphQL
- Schema: Define los tipos de datos y las relaciones entre ellos.
- Query: Solicita datos.
- Mutation: Modifica datos.
- Resolver: Funciones que resuelven una consulta o mutación.
Configuración del Cliente GraphQL en Flutter
Paso 1: Añadir Dependencias
Primero, necesitas añadir las dependencias necesarias en tu archivo pubspec.yaml
.
Paso 2: Configurar el Cliente GraphQL
Configura el cliente GraphQL en tu aplicación Flutter. Esto generalmente se hace en el archivo main.dart
.
import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; void main() async { await initHiveForFlutter(); final HttpLink httpLink = HttpLink( 'https://your-graphql-endpoint.com/graphql', ); final GraphQLClient client = GraphQLClient( cache: GraphQLCache(store: HiveStore()), link: httpLink, ); runApp(MyApp(client: client)); } class MyApp extends StatelessWidget { final GraphQLClient client; MyApp({required this.client}); @override Widget build(BuildContext context) { return GraphQLProvider( client: ValueNotifier(client), child: MaterialApp( home: HomeScreen(), ), ); } }
Paso 3: Realizar una Consulta GraphQL
Para realizar una consulta, puedes usar el widget Query
proporcionado por graphql_flutter
.
import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { String readRepositories = """ query ReadRepositories { viewer { repositories(last: 50) { nodes { name } } } } """; return Scaffold( appBar: AppBar( title: Text('GraphQL Integration'), ), body: Query( options: QueryOptions( document: gql(readRepositories), ), builder: (QueryResult result, { VoidCallback? refetch, FetchMore? fetchMore }) { if (result.hasException) { return Text(result.exception.toString()); } if (result.isLoading) { return Center(child: CircularProgressIndicator()); } List repositories = result.data!['viewer']['repositories']['nodes']; return ListView.builder( itemCount: repositories.length, itemBuilder: (context, index) { return ListTile( title: Text(repositories[index]['name']), ); }, ); }, ), ); } }
Paso 4: Realizar una Mutación GraphQL
Para realizar una mutación, puedes usar el widget Mutation
.
import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; class AddRepositoryScreen extends StatelessWidget { @override Widget build(BuildContext context) { String addRepository = """ mutation AddRepository(\$name: String!) { createRepository(input: {name: \$name}) { repository { id name } } } """; return Scaffold( appBar: AppBar( title: Text('Add Repository'), ), body: Mutation( options: MutationOptions( document: gql(addRepository), ), builder: (RunMutation runMutation, QueryResult? result) { return Column( children: [ TextField( decoration: InputDecoration(labelText: 'Repository Name'), onSubmitted: (name) { runMutation({'name': name}); }, ), if (result != null && result.hasException) Text(result.exception.toString()), if (result != null && result.isLoading) CircularProgressIndicator(), if (result != null && result.data != null) Text('Repository Added: ${result.data!['createRepository']['repository']['name']}'), ], ); }, ), ); } }
Manejo de Errores y Respuestas
Es importante manejar adecuadamente los errores y las respuestas de las consultas y mutaciones GraphQL.
Errores Comunes
- Errores de red: Problemas de conectividad.
- Errores de sintaxis: Errores en la consulta o mutación.
- Errores de autorización: Falta de permisos para acceder a ciertos datos.
Manejo de Errores
Puedes manejar los errores verificando la propiedad hasException
del QueryResult
.
Ejercicio Práctico
Ejercicio 1: Realizar una Consulta
- Configura un cliente GraphQL en tu aplicación Flutter.
- Realiza una consulta para obtener una lista de usuarios desde un endpoint GraphQL.
- Muestra los nombres de los usuarios en una lista.
Ejercicio 2: Realizar una Mutación
- Configura una mutación para añadir un nuevo usuario.
- Crea un formulario con un campo de texto para ingresar el nombre del usuario.
- Ejecuta la mutación al enviar el formulario y muestra un mensaje de éxito o error.
Soluciones
Solución Ejercicio 1
import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; void main() async { await initHiveForFlutter(); final HttpLink httpLink = HttpLink( 'https://your-graphql-endpoint.com/graphql', ); final GraphQLClient client = GraphQLClient( cache: GraphQLCache(store: HiveStore()), link: httpLink, ); runApp(MyApp(client: client)); } class MyApp extends StatelessWidget { final GraphQLClient client; MyApp({required this.client}); @override Widget build(BuildContext context) { return GraphQLProvider( client: ValueNotifier(client), child: MaterialApp( home: UserListScreen(), ), ); } } class UserListScreen extends StatelessWidget { @override Widget build(BuildContext context) { String readUsers = """ query ReadUsers { users { id name } } """; return Scaffold( appBar: AppBar( title: Text('User List'), ), body: Query( options: QueryOptions( document: gql(readUsers), ), builder: (QueryResult result, { VoidCallback? refetch, FetchMore? fetchMore }) { if (result.hasException) { return Text(result.exception.toString()); } if (result.isLoading) { return Center(child: CircularProgressIndicator()); } List users = result.data!['users']; return ListView.builder( itemCount: users.length, itemBuilder: (context, index) { return ListTile( title: Text(users[index]['name']), ); }, ); }, ), ); } }
Solución Ejercicio 2
import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; class AddUserScreen extends StatelessWidget { @override Widget build(BuildContext context) { String addUser = """ mutation AddUser(\$name: String!) { createUser(input: {name: \$name}) { user { id name } } } """; return Scaffold( appBar: AppBar( title: Text('Add User'), ), body: Mutation( options: MutationOptions( document: gql(addUser), ), builder: (RunMutation runMutation, QueryResult? result) { return Column( children: [ TextField( decoration: InputDecoration(labelText: 'User Name'), onSubmitted: (name) { runMutation({'name': name}); }, ), if (result != null && result.hasException) Text(result.exception.toString()), if (result != null && result.isLoading) CircularProgressIndicator(), if (result != null && result.data != null) Text('User Added: ${result.data!['createUser']['user']['name']}'), ], ); }, ), ); } }
Conclusión
En esta sección, has aprendido cómo integrar GraphQL en tu aplicación Flutter. Has configurado un cliente GraphQL, realizado consultas y mutaciones, y manejado errores y respuestas. Con estos conocimientos, puedes aprovechar las ventajas de GraphQL para construir aplicaciones más eficientes y flexibles.
En el próximo módulo, exploraremos cómo manejar la persistencia y el almacenamiento en Flutter, incluyendo el uso de bases de datos locales y almacenamiento de archivos.
Curso de Desarrollo con Flutter
Módulo 1: Introducción a Flutter
- ¿Qué es Flutter?
- Configuración del Entorno de Desarrollo
- Entendiendo la Arquitectura de Flutter
- Creando Tu Primera App con Flutter
Módulo 2: Conceptos Básicos de Programación en Dart
- Introducción a Dart
- Variables y Tipos de Datos
- Sentencias de Control de Flujo
- Funciones y Métodos
- Programación Orientada a Objetos en Dart
Módulo 3: Widgets en Flutter
- Introducción a los Widgets
- Widgets Stateless vs Stateful
- Widgets Básicos
- Widgets de Diseño
- Widgets de Entrada y Formularios
Módulo 4: Gestión de Estado
Módulo 5: Navegación y Enrutamiento
- Introducción a la Navegación
- Navegación Básica
- Rutas Nombradas
- Pasando Datos Entre Pantallas
- Deep Linking
Módulo 6: Redes y APIs
- Obteniendo Datos de Internet
- Parseo de Datos JSON
- Manejo de Errores de Red
- Usando APIs REST
- Integración con GraphQL
Módulo 7: Persistencia y Almacenamiento
- Introducción a la Persistencia
- Preferencias Compartidas
- Almacenamiento de Archivos
- Base de Datos SQLite
- Usando Hive para Almacenamiento Local
Módulo 8: Conceptos Avanzados de Flutter
- Animaciones en Flutter
- Custom Paint y Canvas
- Canales de Plataforma
- Isolates y Concurrencia
- Optimización de Rendimiento
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias
- Pruebas de Widgets
- Pruebas de Integración
- Técnicas de Depuración
Módulo 10: Despliegue y Mantenimiento
- Preparación para el Lanzamiento
- Construcción para iOS
- Construcción para Android
- Integración Continua/Despliegue Continuo (CI/CD)
- Mantenimiento y Actualización de Tu App