GraphQL Generation
GraphQL is delivered via the GraphQL plugin. Enable it with --gql to generate queries, mutations, and subscriptions from entities and custom use cases.
Overview
GraphQL generation in Zuraffa eliminates the boilerplate of writing GraphQL operation strings by hand. With a single command, you can generate:
- Queries for fetching data
- Mutations for modifying data
- Subscriptions for real-time updates
All generated as Dart string constants that work seamlessly with any GraphQL client library.
Why GraphQL Generation?
- Type Safety: Generated operations match your entity and UseCase types
- No Manual Strings: No need to maintain inline GraphQL strings
- Auto-Detection: Operation types are automatically detected for entity methods
- Consistency: Ensures all team members use the same field selections
- Refactoring Ready: Change your entity structure, regenerate GraphQL operations
How It Works
- Define your entities or custom UseCases
- Add the
--gqlflag to your generation command - Specify return fields and other GraphQL options
- Generated files appear in
data/data_sources/{entity}/graphql/ - Use with any GraphQL client (graphql_flutter, ferry, etc.)
Entity-Based Generation
Generate GraphQL operations for entity CRUD methods:
# Basic GraphQL generation
zfa generate Product --methods=get,getList,create --gql
# With custom return fields
zfa generate Product \
--methods=get,getList,create,update,delete \
--gql \
--gql-returns="id,name,description,price,category,isActive,createdAt,updatedAt"
# Complete GraphQL setup with data layer
zfa generate Product \
--methods=get,getList,create,update,delete,watch,watchList \
--data \
--gql \
--gql-returns="id,name,description,price,category,isActive,createdAt,updatedAt" \
--di
Generated Files Structure
lib/src/data/data_sources/product/graphql/
├── get_product_query.dart
├── get_product_list_query.dart
├── create_product_mutation.dart
├── update_product_mutation.dart
├── delete_product_mutation.dart
├── watch_product_subscription.dart
└── watch_product_list_subscription.dart
Generated Code Examples
Query:
// Generated GraphQL query for GetProduct
const String getProductQuery = r'''
query GetProduct($id: String!) {
getProduct(id: $id) {
id
name
description
price
category
isActive
createdAt
updatedAt
}
}''';
Mutation:
// Generated GraphQL mutation for CreateProduct
const String createProductMutation = r'''
mutation CreateProduct($input: CreateProductInput!) {
createProduct(input: $input) {
id
name
description
price
category
isActive
createdAt
}
}''';
Subscription:
// Generated GraphQL subscription for WatchProductList
const String watchProductListSubscription = r'''
subscription WatchProductList {
watchProductList {
id
name
price
category
isActive
updatedAt
}
}''';
Custom UseCase Generation
Generate GraphQL operations for custom UseCases that use services:
# Custom UseCase with query
zfa generate SearchProducts \
--service=Search \
--domain=products \
--params=SearchQuery \
--returns=List<Product> \
--gql \
--gql-type=query \
--gql-name=searchProducts \
--gql-input-type=SearchInput \
--gql-returns="id,name,price,category,rating"
# Custom UseCase with mutation
zfa generate UploadFile \
--service=Storage \
--domain=storage \
--params=FileData \
--returns=String \
--gql \
--gql-type=mutation \
--gql-name=uploadFile \
--gql-input-type=FileInput
# Custom UseCase with subscription
zfa generate WatchUserLocation \
--service=Location \
--domain=realtime \
--params=UserId \
--returns=Location \
--gql \
--gql-type=subscription
Generated Code Example
Custom Query:
// Generated GraphQL query for SearchProducts
const String searchProductsQuery = r'''
query SearchProducts($input: SearchInput!) {
searchProducts(input: $input) {
id
name
price
category
rating
}
}''';
Using Generated GraphQL
With graphql_flutter
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:zuraffa_example/data/data_sources/product/graphql/get_product_query.dart';
import 'package:zuraffa_example/data/data_sources/product/graphql/create_product_mutation.dart';
class ProductGraphQLDataSource {
final GraphQLClient _client;
ProductGraphQLDataSource(this._client);
Future<Product> getProduct(String id) async {
final result = await _client.query(
QueryOptions(
document: gql(getProductQuery),
variables: {'id': id},
),
);
if (result.hasException) {
throw Exception('Failed to fetch product: ${result.exception}');
}
return Product.fromJson(result.data!['getProduct']);
}
Future<Product> createProduct(CreateProductInput input) async {
final result = await _client.mutate(
MutationOptions(
document: gql(createProductMutation),
variables: {'input': input.toJson()},
),
);
if (result.hasException) {
throw Exception('Failed to create product: ${result.exception}');
}
return Product.fromJson(result.data!['createProduct']);
}
Stream<List<Product>> watchProductList() {
return _client.subscribe(
SubscriptionOptions(
document: gql(watchProductListSubscription),
),
);
}
}
With Ferry
import 'package:ferry/ferry.dart';
import 'package:ferry/graphql_flutter.dart';
import 'package:zuraffa_example/data/data_sources/product/graphql/get_product_query.dart';
class ProductGraphQLDataSource {
final Client _client;
ProductGraphQLDataSource(this._client);
Stream<Product> getProduct(String id) {
return _client.request(GetProductReq((b) => b
..vars.id = id
));
}
}
Direct String Usage
import 'package:http/http.dart' as http;
import 'package:zuraffa_example/data/data_sources/product/graphql/get_product_query.dart';
class ProductGraphQLDataSource {
final String _endpoint;
final http.Client _httpClient;
ProductGraphQLDataSource(this._endpoint, this._httpClient);
Future<Product> getProduct(String id) async {
final response = await _httpClient.post(
Uri.parse(_endpoint),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'query': getProductQuery,
'variables': {'id': id},
}),
);
if (response.statusCode != 200) {
throw Exception('Failed to fetch product');
}
return Product.fromJson(json.decode(response.body)['data']['getProduct']);
}
}
GraphQL Flags Reference
| Flag | Description | Example |
|---|---|---|
--gql | Enable GraphQL generation | --gql |
--gql-type | Operation type: query, mutation, subscription | --gql-type=query |
--gql-returns | Return fields (comma-separated) | --gql-returns="id,name,price" |
--gql-input-type | Input type name for mutation/subscription | --gql-input-type=ProductInput |
--gql-input-name | Input variable name (default: input) | --gql-input-name=request |
--gql-name | Custom operation name | --gql-name=getProductById |
Auto-Detection
For entity-based generation, operation types are automatically detected:
| Method | Auto-Detected Type |
|---|---|
get | query |
getList | query |
create | mutation |
update | mutation |
delete | mutation |
watch | subscription |
watchList | subscription |
For custom UseCases, you must specify --gql-type explicitly.
Nested Fields
Specify nested fields in --gql-returns using dot notation:
zfa generate Order --methods=get \
--gql \
--gql-returns="id,createdAt,customer{id,name,email},items{id,quantity,price,product{id,name}}"
Generated:
const String getOrderQuery = r'''
query GetOrder($id: String!) {
getOrder(id: $id) {
id
createdAt
customer {
id
name
email
}
items {
id
quantity
price
product {
id
name
}
}
}
}''';
Custom Operation Names
Override auto-generated operation names with --gql-name:
# Default operation name: GetProduct (from method 'get')
zfa generate Product --methods=get --gql
# Custom operation name: GetProductById
zfa generate Product --methods=get --gql --gql-name=GetProductById
Coming Soon
We're working on even more powerful GraphQL features:
Schema-First Generation
- Auto-generate entities from GraphQL schema: Import your GraphQL schema and Zuraffa will automatically create all entity definitions
- Auto-generate UseCases from queries/mutations: Parse your
.graphqlfiles and generate corresponding UseCases with proper types - Type safety from schema to code: Ensure complete type alignment between your GraphQL server and Flutter app
- Introspection support: Fetch live schema from GraphQL server to generate up-to-date types
- Federation support: Generate code for federated GraphQL schemas
Benefits
These features will make building GraphQL-powered Flutter apps even more seamless:
- Zero Boilerplate: No manual entity creation from schema
- Always Synced: Your Flutter types will always match your server schema
- Type Safety End-to-End: From database to UI, fully typed
- Live Updates: Fetch introspection on build to catch breaking changes early
- Federation Ready: Support for complex GraphQL federation setups
Planned Features
# Import schema and generate everything
zfa generate-from-schema https://api.example.com/graphql
# Parse .graphql files and create UseCases
zfa generate-usecases queries/*.graphql
# Watch schema for changes
zfa watch-schema --endpoint https://api.example.com/graphql
Best Practices
- Specify Return Fields: Always provide
--gql-returnsto avoid over-fetching - Use Nested Fields: Leverage GraphQL's nested querying capabilities
- Custom Input Types: Use
--gql-input-typefor complex mutations - Version Your Operations: Use
--gql-nameto maintain API compatibility - Regenerate on Schema Changes: Keep your GraphQL operations in sync with server
Examples
E-commerce App
# Product CRUD with GraphQL
zfa generate Product \
--methods=get,getList,create,update,delete \
--data \
--gql \
--gql-returns="id,name,price,category,images,stock,isActive" \
--vpc --state --di
# Order management with GraphQL
zfa generate Order \
--methods=get,getList,create,update \
--data \
--gql \
--gql-returns="id,total,status,items{id,quantity,price},customer{id,name,address}" \
--vpc --state --di
# Real-time order updates
zfa generate Order --methods=watchList \
--gql --gql-type=subscription \
--gql-returns="id,status,updatedAt"
Chat Application
# Messages with GraphQL subscription
zfa generate Message \
--methods=get,getList,create \
--data \
--gql \
--gql-returns="id,content,sender{id,name},createdAt"
# Real-time chat updates
zfa generate Message \
--methods=watchList \
--gql --gql-type=subscription \
--gql-returns="id,content,sender{id,name},createdAt,updatedAt"
# User status with subscription
zfa generate User \
--methods=watch \
--gql --gql-type=subscription \
--gql-returns="id,name,status,lastSeen"
See Also
- GraphQL Documentation - Official GraphQL documentation
- graphql_flutter - Popular GraphQL client for Flutter
- Ferry - Type-safe GraphQL client
- Result Type - Type-safe error handling
- Service Pattern - Alternative to Repository pattern