mk_graphql_generator
An ultra-fast, intelligent build_runner code generator for mk_graphql. Generates immutable Freezed models, typed operation requests, and convenient GraphQLClient extension methods directly from .graphql and .gql files.
π Full documentation β getting started, build.yaml configuration, generated file layout, and model-sharing rules.
β¨ Features
- β‘ Lightning-Fast Generation: Two-tier caching (memory + disk) with microsecond output path computation so
build_runnernever hangs. - βοΈ Modern Freezed Models: Generates
@freezedmodels and@JsonSerializableclasses for all operations, inputs, and schema models. - π― Direct GraphQLClient Extensions: Generates typed methods on
GraphQLClient(e.g.client.getUser(...),client.getUserStream(...), andclient.refetchGetUser(...)). - π§© Shared vs. Partial Models: Schema models (
{Type}Model) are strictly non-nullable; queries selecting partial fields generate operation-scoped{Type}PartialModelclasses. - π€ Dart Reserved Keyword Mapping: Automatically renames reserved keywords (e.g.
default,class,is,native,switch) tog{Keyword}with exact wire@JsonKey(name: raw). - ποΈ Conditional Directives: Supports
@includeand@skipby generating conditional fields as nullable in response models. - π Dio CancelToken Support: Generated requests and client extensions natively accept
CancelToken? cancelToken. - π GraphQL Multipart Uploads: Built-in mapping of
Uploadscalar toMultipartFile. - βοΈ Custom Scalars & Path Config: Simple
build.yamlmapping for custom types and output directories. - π Schema Introspection CLI: Built-in CLI command to introspect any GraphQL endpoint via HTTP and emit clean standard GraphQL SDL (
.graphqlor.gql).
π Schema Introspection CLI
Generate your schema.graphql directly from a live GraphQL API with a single command:
# Automatically detects schema_path from build.yaml:
dart run mk_graphql_generator:introspect --url https://graphql.anilist.co
# Or specify custom options:
dart run mk_graphql_generator:introspect \
--url https://graphql.anilist.co \
--header "Referer: https://anilist.co/graphiql"
CLI Options:
| Flag | Description | Default |
|---|---|---|
-u, --url |
Target GraphQL HTTP endpoint (required) | β |
-o, --output |
Destination path for SDL output | Automatically resolved from build.yaml (schema_path) |
-c, --build-yaml |
Path to build.yaml configuration file |
build.yaml |
-H, --header |
Custom HTTP headers ("Name: Value"), can be repeated |
β |
-h, --help |
Show usage help | β |
The CLI executes a standard full GraphQL introspection query, parses the schema types, inputs, enums, unions, interfaces, and directives, and outputs clean, valid GraphQL SDL. If --output is omitted, it automatically reads your build.yaml to detect your configured schema_path.
π¦ Installation
Add mk_graphql to your dependencies, and mk_graphql_generator along with code-generation tools to your dev_dependencies:
dependencies:
flutter:
sdk: flutter
mk_graphql: ^1.0.1
freezed_annotation: ^3.1.0
json_annotation: ^4.12.0
dev_dependencies:
flutter_test:
sdk: flutter
mk_graphql_generator: ^1.0.1
build_runner: ^2.16.0
freezed: ^4.0.1
json_serializable: ^6.14.1
π Step-by-Step Integration
1. Place Your Schema
Place your GraphQL schema file under lib/ (e.g. lib/graphql/schema.graphql):
# lib/graphql/schema.graphql
type Query {
user(id: ID!): User
countries(filter: CountryFilterInput): [Country!]!
}
type Mutation {
updateUser(id: ID!, name: String!): User!
}
type User {
id: ID!
name: String!
email: String!
avatar: String
}
input CountryFilterInput {
code: StringQueryOperatorInput
}
input StringQueryOperatorInput {
eq: String
}
type Country {
code: ID!
name: String!
capital: String
emoji: String!
}
2. Write Operation Files
Write your queries, mutations, or subscriptions in .graphql or .gql files anywhere under lib/:
# lib/features/countries/get_countries.graphql
query GetCountries($filter: CountryFilterInput) {
countries(filter: $filter) {
code
name
capital
emoji
}
}
# lib/features/user/get_user.graphql
query GetUser($id: ID!) {
user(id: $id) {
id
name
}
}
3. Configure build.yaml (Optional)
Create a build.yaml file in your project root to customize options:
targets:
$default:
builders:
mk_graphql_generator:mk_graphql_builder:
options:
# Path to schema (defaults to auto-detecting schema.graphql under lib/)
schema_path: lib/graphql/schema.graphql
# Directory for shared models, inputs, and enums (default: lib/shared/generated)
shared_dir: lib/shared/generated
# Enable disk + memory generation caching (default: true)
cache: true
# Map custom scalars to Dart types
scalars:
DateTime: DateTime
UUID: String
Upload: MultipartFile
4. Run Code Generation
Execute build_runner:
dart run build_runner build --delete-conflicting-outputs
Or watch for continuous compilation while you code:
dart run build_runner watch --delete-conflicting-outputs
5. Use the Generated Code
The generator creates:
- Typed variables (
GetCountriesVars) - Typed response models (
GetCountriesModel) - Request classes (
GetCountriesReq) - Direct
GraphQLClientextension methods (client.getCountries(...),client.getCountriesStream(...),client.refetchGetCountries(...))
Example: Calling Operations
import 'package:mk_graphql/mk_graphql.dart';
import 'package:my_app/features/countries/generated/get_countries.gql.dart';
final client = GraphQLClient(url: 'https://api.example.com/graphql');
// Option A: Direct client extension method
final data = await client.getCountries(
filter: const CountryFilterInput(
code: StringQueryOperatorInput(eq: 'NP'),
),
);
// Option B: Typed request object
final req = GetCountriesReq(
variables: const GetCountriesVars(
filter: CountryFilterInput(
code: StringQueryOperatorInput(eq: 'NP'),
),
),
);
final data2 = await client.future(req);
π§© Advanced Codegen Features
Partial Models ({Type}PartialModel)
When a query selects only a partial subset of fields from a schema type, mk_graphql_generator generates an operation-scoped partial model named {Type}PartialModel (e.g. CountryPartialModel). If the query requests all required fields, it uses the shared schema model {Type}Model.
Reserved Keywords (g{Keyword})
GraphQL fields or arguments that match Dart reserved keywords (such as default, class, is, native, switch) are safely transformed to g{Keyword} in Dart with @JsonKey(name: 'raw_name'), avoiding syntax conflicts:
@JsonKey(name: 'default') final bool? gDefault;
Conditional Directives (@include / @skip)
Fields marked with @include(if: $flag) or @skip(if: $flag) are generated as nullable (FieldType?) in response models even if non-null in the GraphQL schema, preventing runtime deserialization crashes when the server omits them.
π License
This project is licensed under the MIT License - see the LICENSE file for details.
Libraries
- builder
- mk_graphql_generator
- Code generator for mk_graphql.