Search code examples
flutterdarttypesgraphqlcode-generation

How to generate Dart from GraphQL - graphql to dart generator


How can simple object types [1] such as interfaces &/ classes be generated from GraphQL schema definitions into Dart?

  • Motivation
    • One single source of truth: GraphQL schema
    • From GraphQL all plain simple types are generated into multiple languages
      • in our case Typescript and Dart
  • what we've tried so far
    • All solutions related [2] - even forks - does not do simple types
  • Possible DIY approaches we know of
    • GraphQL Code Generator [3]
    • quicktype similar alternatives [4]

GraphQL into Typescript example

Given this schema definition

type Person {
    age: Int
    name: String!
}

Running this script

import { GraphQLDefinitionsFactory } from '@nestjs/graphql';
import { join } from 'path';


const definitionsFactory = new GraphQLDefinitionsFactory();

definitionsFactory.generate({
    typePaths: ['./**/*.graphql'],
    path: join(process.cwd(), './class.ts'),
    outputAs: 'class'
});

definitionsFactory.generate({
    typePaths: ['./src/**/*.graphql'],
    path: join(process.cwd(), './interface.ts'),
    outputAs: 'interface'
});

Output

export interface Person {
    age?: number;
    name: string;
}
export class Person {
    age?: number;
    name: string;
}

1: Simple Object Types should be just simple plain object types without annotations, encoding and decoding logic etc. 2: https://github.com/gql-dart/gql
3: https://graphql-code-generator.com
4: https://app.quicktype.io


Solution

  • I personally tried to use Artemis or hoped Apollo was branching out, but @Ryosuke's graphql_to_dart is straight forward and lean.

    If you already have a GraphQL endpoint with your schema up and running, you just need to set up its graphql_config.yaml for example like this:

    package_name: example
    graphql_endpoint: http://example.com/graphql
    models_directory_path: lib/graphql/models/
    

    Given schema definition

    type Person {
        age: Int
        name: String!
    }
    

    .dart Output

    class Person{
      int age;
      String name;
      Person({
        this.age,this.name
      });
    
      Person.fromJson(Map<String, dynamic> json){
        age = json['age'];
        name = json['name'];
      }
    
      Map toJson(){
        Map _data = {};
        _data['age'] = age;
        _data['name'] = name;
        return _data;
      }
    }
    

    With the additional option type_override you can set custom scalar types as you prefer them.

    Edit:

    There is now an expanded version as PR. With the possibility to generate them outside of lib/ without import path conflicts, through an opt-out option dynamic_import_path: false.

    The type_override keys also don't need to be explicitly written in lower case anymore.