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.

dependencies:
  flutter:
    sdk: flutter
  graphql_flutter: ^5.0.0

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.

if (result.hasException) {
  return Text(result.exception.toString());
}

Ejercicio Práctico

Ejercicio 1: Realizar una Consulta

  1. Configura un cliente GraphQL en tu aplicación Flutter.
  2. Realiza una consulta para obtener una lista de usuarios desde un endpoint GraphQL.
  3. Muestra los nombres de los usuarios en una lista.

Ejercicio 2: Realizar una Mutación

  1. Configura una mutación para añadir un nuevo usuario.
  2. Crea un formulario con un campo de texto para ingresar el nombre del usuario.
  3. 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

Módulo 2: Conceptos Básicos de Programación en Dart

Módulo 3: Widgets en Flutter

Módulo 4: Gestión de Estado

Módulo 5: Navegación y Enrutamiento

Módulo 6: Redes y APIs

Módulo 7: Persistencia y Almacenamiento

Módulo 8: Conceptos Avanzados de Flutter

Módulo 9: Pruebas y Depuración

Módulo 10: Despliegue y Mantenimiento

Módulo 11: Flutter para Web y Escritorio

© Copyright 2024. Todos los derechos reservados