Back to skills
SKILL.md
Graphql
ASecurity| Atributo | Valor | |----------|-------| | **ID** | `flutter-graphql` | | **Nivel** | π΄ Avanzado | | **VersiΓ³n** | 1.0.0 | | **Keywords** | `graphql`, `apollo`, `graphql-client`, `subscriptions` | | **Referencia** | [GraphQL Flutter](https://pub.dev/packages/graphql_flutter) |
- 4 stars
- 0 votes
- 0 copies
- 4 views
- Added September 8, 2026
Works with
Security analysis
100/100npx -y skills add chimeranext/flutter-boilerplate-monorepo-template --skill graphql --agent claude-codeAre you the author of Graphql?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/chimeranext-graphql)# π Skill: GraphQL Integration
## π Metadata
| Atributo | Valor |
|----------|-------|
| **ID** | `flutter-graphql` |
| **Nivel** | π΄ Avanzado |
| **VersiΓ³n** | 1.0.0 |
| **Keywords** | `graphql`, `apollo`, `graphql-client`, `subscriptions` |
| **Referencia** | [GraphQL Flutter](https://pub.dev/packages/graphql_flutter) |
## π Keywords para InvocaciΓ³n
- `graphql`
- `apollo`
- `graphql-client`
- `subscriptions`
- `mutations`
- `@skill:graphql`
### Ejemplos de Prompts
```
Integra GraphQL para consultas y mutaciones
```
```
Implementa GraphQL con subscriptions en tiempo real
```
```
@skill:graphql - Configura cliente GraphQL con cache
```
## π DescripciΓ³n
GraphQL Integration permite consultar APIs GraphQL con queries, mutations y subscriptions en tiempo real. Incluye cache automΓ‘tico, optimistic updates, paginaciΓ³n, manejo de errores y code generation.
### β
CuΓ‘ndo Usar Este Skill
- Backend usa GraphQL
- Necesitas queries flexibles
- Datos en tiempo real (subscriptions)
- Optimistic UI updates
- Cache inteligente del lado del cliente
- Reducir over-fetching/under-fetching
### β CuΓ‘ndo NO Usar Este Skill
- Backend solo REST
- App muy simple
- Team no familiarizado con GraphQL
## ποΈ Estructura del Proyecto
```
lib/
βββ core/
β βββ graphql/
β β βββ graphql_client.dart
β β βββ graphql_config.dart
β β βββ graphql_link.dart
β β βββ cache_config.dart
β βββ utils/
β βββ graphql_helpers.dart
β
βββ features/
β βββ products/
β βββ data/
β β βββ datasources/
β β β βββ products_graphql_datasource.dart
β β βββ models/
β β β βββ product_model.dart
β β βββ repositories/
β β βββ products_repository_impl.dart
β βββ domain/
β β βββ entities/
β β β βββ product.dart
β β βββ repositories/
β β βββ products_repository.dart
β βββ presentation/
β βββ bloc/
β β βββ products_bloc.dart
β βββ screens/
β βββ products_screen.dart
β
βββ graphql/
βββ queries/
β βββ get_products.graphql
β βββ get_product.graphql
βββ mutations/
β βββ create_product.graphql
β βββ update_product.graphql
β βββ delete_product.graphql
βββ subscriptions/
βββ product_updated.graphql
```
## π¦ Dependencias Requeridas
```yaml
dependencies:
flutter:
sdk: flutter
# GraphQL Client
graphql_flutter: ^5.1.2
# Code Generation (opcional)
gql: ^1.0.0
ferry: ^0.15.0
ferry_flutter: ^0.9.0
# Utils
equatable: ^2.0.5
dartz: ^0.10.1
# State Management
flutter_bloc: ^8.1.3
dev_dependencies:
# Code Generation
build_runner: ^2.4.6
ferry_generator: ^0.10.0
gql_code_builder: ^0.7.0
```
### graphql/schema.graphql
```graphql
type Query {
products(limit: Int, offset: Int): [Product!]!
product(id: ID!): Product
searchProducts(query: String!): [Product!]!
}
type Mutation {
createProduct(input: CreateProductInput!): Product!
updateProduct(id: ID!, input: UpdateProductInput!): Product!
deleteProduct(id: ID!): Boolean!
}
type Subscription {
productUpdated(id: ID!): Product!
productCreated: Product!
}
type Product {
id: ID!
name: String!
description: String!
price: Float!
imageUrl: String!
stock: Int!
createdAt: String!
updatedAt: String!
}
input CreateProductInput {
name: String!
description: String!
price: Float!
imageUrl: String!
stock: Int!
}
input UpdateProductInput {
name: String
description: String
price: Float
imageUrl: String
stock: Int
}
```
## π» ImplementaciΓ³n
### 1. GraphQL Client Configuration
```dart
// lib/core/graphql/graphql_config.dart
import 'package:graphql_flutter/graphql_flutter.dart';
class GraphQLConfig {
static const String _endpoint = 'https://api.example.com/graphql';
static const String _wsEndpoint = 'wss://api.example.com/graphql';
static HttpLink get httpLink => HttpLink(_endpoint);
static WebSocketLink get websocketLink => WebSocketLink(
_wsEndpoint,
config: const SocketClientConfig(
autoReconnect: true,
inactivityTimeout: Duration(seconds: 30),
),
);
static AuthLink get authLink => AuthLink(
getToken: () async {
// Obtener token de autenticaciΓ³n
// final token = await SecureStorage.getToken();
return 'Bearer YOUR_TOKEN';
},
);
static Link get link {
final Link httpLinkWithAuth = authLink.concat(httpLink);
// Combinar HTTP y WebSocket links
return Link.split(
(request) => request.isSubscription,
websocketLink,
httpLinkWithAuth,
);
}
static GraphQLClient getClient() {
return GraphQLClient(
link: link,
cache: GraphQLCache(
store: HiveStore(),
),
defaultPolicies: DefaultPolicies(
query: Policies(
fetch: FetchPolicy.cacheFirst,
error: ErrorPolicy.all,
cacheReread: CacheRereadPolicy.mergeOptimistic,
),
mutate: Policies(
fetch: FetchPolicy.networkOnly,
error: ErrorPolicy.all,
),
subscribe: Policies(
fetch: FetchPolicy.networkOnly,
error: ErrorPolicy.all,
),
),
);
}
}
```
### 2. GraphQL Queries
```graphql
# graphql/queries/get_products.graphql
query GetProducts($limit: Int, $offset: Int) {
products(limit: $limit, offset: $offset) {
id
name
description
price
imageUrl
stock
createdAt
updatedAt
}
}
```
```graphql
# graphql/queries/get_product.graphql
query GetProduct($id: ID!) {
product(id: $id) {
id
name
description
price
imageUrl
stock
createdAt
updatedAt
}
}
```
```graphql
# graphql/queries/search_products.graphql
query SearchProducts($query: String!) {
searchProducts(query: $query) {
id
name
description
price
imageUrl
stock
}
}
```
### 3. GraphQL Mutations
```graphql
# graphql/mutations/create_product.graphql
mutation CreateProduct($input: CreateProductInput!) {
createProduct(input: $input) {
id
name
description
price
imageUrl
stock
createdAt
updatedAt
}
}
```
```graphql
# graphql/mutations/update_product.graphql
mutation UpdateProduct($id: ID!, $input: UpdateProductInput!) {
updateProduct(id: $id, input: $input) {
id
name
description
price
imageUrl
stock
updatedAt
}
}
```
```graphql
# graphql/mutations/delete_product.graphql
mutation DeleteProduct($id: ID!) {
deleteProduct(id: $id)
}
```
### 4. GraphQL Subscriptions
```graphql
# graphql/subscriptions/product_updated.graphql
subscription ProductUpdated($id: ID!) {
productUpdated(id: $id) {
id
name
description
price
imageUrl
stock
updatedAt
}
}
```
```graphql
# graphql/subscriptions/product_created.graphql
subscription ProductCreated {
productCreated {
id
name
description
price
imageUrl
stock
createdAt
}
}
```
### 5. DataSource Implementation
```dart
// lib/features/products/data/datasources/products_graphql_datasource.dart
import 'package:graphql_flutter/graphql_flutter.dart';
import '../models/product_model.dart';
abstract class ProductsGraphQLDataSource {
Future<List<ProductModel>> getProducts({int? limit, int? offset});
Future<ProductModel> getProduct(String id);
Future<List<ProductModel>> searchProducts(String query);
Future<ProductModel> createProduct(ProductModel product);
Future<ProductModel> updateProduct(ProductModel product);
Future<bool> deleteProduct(String id);
Stream<ProductModel> subscribeToProductUpdates(String id);
}
class ProductsGraphQLDataSourceImpl implements ProductsGraphQLDataSource {
final GraphQLClient client;
ProductsGraphQLDataSourceImpl(this.client);
static const String _getProductsQuery = r'''
query GetProducts($limit: Int, $offset: Int) {
products(limit: $limit, offset: $offset) {
id
name
description
price
imageUrl
stock
createdAt
updatedAt
}
}
''';
static const String _getProductQuery = r'''
query GetProduct($id: ID!) {
product(id: $id) {
id
name
description
price
imageUrl
stock
createdAt
updatedAt
}
}
''';
static const String _searchProductsQuery = r'''
query SearchProducts($query: String!) {
searchProducts(query: $query) {
id
name
description
price
imageUrl
stock
}
}
''';
static const String _createProductMutation = r'''
mutation CreateProduct($input: CreateProductInput!) {
createProduct(input: $input) {
id
name
description
price
imageUrl
stock
createdAt
updatedAt
}
}
''';
static const String _updateProductMutation = r'''
mutation UpdateProduct($id: ID!, $input: UpdateProductInput!) {
updateProduct(id: $id, input: $input) {
id
name
description
price
imageUrl
stock
updatedAt
}
}
''';
static const String _deleteProductMutation = r'''
mutation DeleteProduct($id: ID!) {
deleteProduct(id: $id)
}
''';
static const String _productUpdatedSubscription = r'''
subscription ProductUpdated($id: ID!) {
productUpdated(id: $id) {
id
name
description
price
imageUrl
stock
updatedAt
}
}
''';
@override
Future<List<ProductModel>> getProducts({int? limit, int? offset}) async {
final result = await client.query(
QueryOptions(
document: gql(_getProductsQuery),
variables: {
'limit': limit,
'offset': offset,
},
fetchPolicy: FetchPolicy.cacheFirst,
),
);
if (result.hasException) {
throw Exception(result.exception.toString());
}
final List<dynamic> productsJson = result.data?['products'] ?? [];
return productsJson
.map((json) => ProductModel.fromJson(json))
.toList();
}
@override
Future<ProductModel> getProduct(String id) async {
final result = await client.query(
QueryOptions(
document: gql(_getProductQuery),
variables: {'id': id},
fetchPolicy: FetchPolicy.cacheFirst,
),
);
if (result.hasException) {
throw Exception(result.exception.toString());
}
final productJson = result.data?['product'];
if (productJson == null) {
throw Exception('Product not found');
}
return ProductModel.fromJson(productJson);
}
@override
Future<List<ProductModel>> searchProducts(String query) async {
final result = await client.query(
QueryOptions(
document: gql(_searchProductsQuery),
variables: {'query': query},
fetchPolicy: FetchPolicy.networkOnly,
),
);
if (result.hasException) {
throw Exception(result.exception.toString());
}
final List<dynamic> productsJson = result.data?['searchProducts'] ?? [];
return productsJson
.map((json) => ProductModel.fromJson(json))
.toList();
}
@override
Future<ProductModel> createProduct(ProductModel product) async {
final result = await client.mutate(
MutationOptions(
document: gql(_createProductMutation),
variables: {
'input': {
'name': product.name,
'description': product.description,
'price': product.price,
'imageUrl': product.imageUrl,
'stock': product.stock,
},
},
// Optimistic response
optimisticResult: {
'createProduct': product.toJson(),
},
),
);
if (result.hasException) {
throw Exception(result.exception.toString());
}
return ProductModel.fromJson(result.data?['createProduct']);
}
@override
Future<ProductModel> updateProduct(ProductModel product) async {
final result = await client.mutate(
MutationOptions(
document: gql(_updateProductMutation),
variables: {
'id': product.id,
'input': {
'name': product.name,
'description': product.description,
'price': product.price,
'imageUrl': product.imageUrl,
'stock': product.stock,
},
},
optimisticResult: {
'updateProduct': product.toJson(),
},
),
);
if (result.hasException) {
throw Exception(result.exception.toString());
}
return ProductModel.fromJson(result.data?['updateProduct']);
}
@override
Future<bool> deleteProduct(String id) async {
final result = await client.mutate(
MutationOptions(
document: gql(_deleteProductMutation),
variables: {'id': id},
),
);
if (result.hasException) {
throw Exception(result.exception.toString());
}
return result.data?['deleteProduct'] ?? false;
}
@override
Stream<ProductModel> subscribeToProductUpdates(String id) {
final subscription = client.subscribe(
SubscriptionOptions(
document: gql(_productUpdatedSubscription),
variables: {'id': id},
),
);
return subscription.map((result) {
if (result.hasException) {
throw Exception(result.exception.toString());
}
return ProductModel.fromJson(result.data?['productUpdated']);
});
}
}
```
### 6. Usage in Widgets
```dart
// lib/features/products/presentation/screens/products_screen.dart
import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
class ProductsScreen extends StatelessWidget {
const ProductsScreen({super.key});
static const String _getProductsQuery = r'''
query GetProducts($limit: Int, $offset: Int) {
products(limit: $limit, offset: $offset) {
id
name
description
price
imageUrl
stock
}
}
''';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Products'),
),
body: Query(
options: QueryOptions(
document: gql(_getProductsQuery),
variables: const {
'limit': 20,
'offset': 0,
},
fetchPolicy: FetchPolicy.cacheAndNetwork,
pollInterval: const Duration(seconds: 30),
),
builder: (result, {fetchMore, refetch}) {
// Loading state
if (result.isLoading && result.data == null) {
return const Center(child: CircularProgressIndicator());
}
// Error state
if (result.hasException) {
return Center(
child: Text('Error: ${result.exception.toString()}'),
);
}
// Success state
final products = result.data?['products'] as List<dynamic>? ?? [];
return RefreshIndicator(
onRefresh: () async {
await refetch?.call();
},
child: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ProductCard(
id: product['id'],
name: product['name'],
price: product['price'],
imageUrl: product['imageUrl'],
);
},
),
);
},
),
);
}
}
```
```dart
// Mutation Example
class CreateProductButton extends StatelessWidget {
final ProductModel product;
const CreateProductButton({required this.product});
static const String _createProductMutation = r'''
mutation CreateProduct($input: CreateProductInput!) {
createProduct(input: $input) {
id
name
price
}
}
''';
@override
Widget build(BuildContext context) {
return Mutation(
options: MutationOptions(
document: gql(_createProductMutation),
onCompleted: (dynamic resultData) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Product created!')),
);
},
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $error')),
);
},
),
builder: (runMutation, result) {
return ElevatedButton(
onPressed: result?.isLoading ?? false
? null
: () {
runMutation({
'input': {
'name': product.name,
'description': product.description,
'price': product.price,
'imageUrl': product.imageUrl,
'stock': product.stock,
},
});
},
child: result?.isLoading ?? false
? const CircularProgressIndicator()
: const Text('Create Product'),
);
},
);
}
}
```
```dart
// Subscription Example
class ProductDetailScreen extends StatelessWidget {
final String productId;
const ProductDetailScreen({required this.productId});
static const String _productUpdatedSubscription = r'''
subscription ProductUpdated($id: ID!) {
productUpdated(id: $id) {
id
name
price
stock
updatedAt
}
}
''';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Product Detail')),
body: Subscription(
options: SubscriptionOptions(
document: gql(_productUpdatedSubscription),
variables: {'id': productId},
),
builder: (result) {
if (result.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (result.hasException) {
return Center(child: Text('Error: ${result.exception}'));
}
final product = result.data?['productUpdated'];
if (product == null) {
return const Center(child: Text('No data'));
}
return Column(
children: [
Text('Name: ${product['name']}'),
Text('Price: \$${product['price']}'),
Text('Stock: ${product['stock']}'),
Text('Updated: ${product['updatedAt']}'),
],
);
},
),
);
}
}
```
## π― Mejores PrΓ‘cticas
### 1. Fragment Reusability
```graphql
fragment ProductFields on Product {
id
name
description
price
imageUrl
stock
}
query GetProducts {
products {
...ProductFields
}
}
```
### 2. Optimistic Updates
```dart
optimisticResult: {
'createProduct': {
'__typename': 'Product',
'id': 'temp-id',
...product.toJson(),
},
}
```
### 3. Error Handling
```dart
if (result.hasException) {
final exception = result.exception;
if (exception?.graphqlErrors != null) {
// Handle GraphQL errors
}
if (exception?.linkException != null) {
// Handle network errors
}
}
```
## π Recursos Adicionales
- [GraphQL Flutter](https://pub.dev/packages/graphql_flutter)
- [GraphQL Official](https://graphql.org/)
- [Ferry Code Generator](https://ferrygraphql.com/)
## π Skills Relacionados
- [Clean Architecture](../clean-architecture/SKILL.md)
- [Offline-First](../offline-first/SKILL.md)
---
**VersiΓ³n:** 1.0.0
**Γltima actualizaciΓ³n:** Diciembre 2025
Attribution
Related skills
View all in development βComments
Loading commentsβ¦
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.