Home

Awesome

json-type-graphql

Generate TypeGraphQL class definition from JSON/Remote API/JSON File.

Start

npm i json-type-graphql --save
yarn add json-type-graphql --save
pnpm i json-type-graphql --save

Current Feature

This project is still under heavy development, the documentation is far from ready, but basic features are already supported:

Example

Run yarn demo to explore!

JSON:

{
  "booleanField": true,
  "numberField": 200,
  "stringField": "success",
  "primitiveArrayField": [1, 2, 3, 4, 5],
  "mixedField": [
    1,
    2,
    {
      "a": "1111111"
    }
  ],
  "emptyArrayField": [],
  "nestedField": {
    "booleanField": true,
    "numberField": 200,
    "stringField": "success",
    "primitiveArrayField": [1, 2, 3, 4, 5],
    "mixedFieldrs": [1, 2]
  }
}
import path from "path";
import fs from "fs-extra";
import transformer from "json-type-garphql";

(async () => {
  await transformer({
    // Provide json file path
    reader: { path: path.join(__dirname, "./demo.json") },
    // Customize parser behaviour
    parser: {
      forceNonNullable: false,
    },
    // Customize generator behaviour
    generator: { entryClassName: "Root", sort: true },
    // Check can generated TypeGraphQL class be used normally
    checker: {
      disable: false,
    },
    // Write generated file!
    writter: {
      outputPath: path.join(__dirname, "./generated.ts"),
    },
  });
})();

More options will be introduced below.

generated:

import { ObjectType, Field, Int, ID } from "type-graphql";

@ObjectType()
export class MixedField {
  @Field()
  a!: string;
}

@ObjectType()
export class EmptyArrayField {}

@ObjectType()
export class NestedField {
  @Field({ nullable: true })
  booleanField?: boolean;

  @Field((type) => Int, { nullable: true })
  numberField?: number;

  @Field({ nullable: true })
  stringField?: string;

  @Field((type) => [Int], { nullable: true })
  primitiveArrayField?: number[];

  @Field((type) => [Int], { nullable: true })
  mixedFieldrs?: number[];
}

@ObjectType()
export class Root {
  @Field({ nullable: true })
  booleanField?: boolean;

  @Field((type) => Int, { nullable: true })
  numberField?: number;

  @Field({ nullable: true })
  stringField?: string;

  @Field((type) => [Int], { nullable: true })
  primitiveArrayField?: number[];

  @Field((type) => [MixedField], { nullable: true })
  mixedField?: MixedField[];

  @Field((type) => [EmptyArrayField], { nullable: true })
  emptyArrayField?: EmptyArrayField[];

  @Field((type) => NestedField, { nullable: true })
  nestedField?: NestedField;
}

Programmatic Usage

import {
  reader,
  parser,
  preprocessor,
  generator,
  writter,
} from "json-type-graphql";

export default async function handler(options: Options): Promise<void> {
  // read from data source you want
  // you can also use custom reader
  const content = await reader(options.reader);

  // make some custom processing
  const preprocessed = preprocessor(content, normalizedPreprocessorOptions);

  // parse content
  const parsedInfo = parser(preprocessed, normalizedParserOptions);

  fs.ensureFileSync(normalizedWritterOptions.outputPath);

  const source = new Project().addSourceFileAtPath(
    normalizedWritterOptions.outputPath
  );

  // generate AST and result!
  generator(source, parsedInfo, normalizedGeneratorOptions);

  // write!
  writter(normalizedWritterOptions);
}

Options

Reader

Reader is responsible for reading data from different sources including JSON File / URL Request / Raw JavaScript Object, you must provide one of reader.path / reader.url / reader.raw options.

Reader.Options

After content acquisition got completed, the content will be passed to next handler called preprocessor.

Preprocessor

Preprocessor will perform some extra pre-processing works in the incoming content:

Preprocessor.Options

Parser

Parser will transform the pre-processed content to specific object structure, which will be consumed by generator.

Array entry structure(like []) and object entry structure(like {}) will be parsed differently.

Parser.Options

Generator

Generator will traverse the parsed info, perform corresponding AST operations to generate class definitions with TypeGraphQL decorators.

Generator.Options

Postprocessor

Postprocessor is used to apply some post-process works on generated source (TypeScript SourceFile), you can use ts-morph for simple and flexiable AST operations, which also powers the generator part indeed.

Postprocessor.Options

Checker

Checker will use generated class definitions to create a tmp reoslver, invoking TypeGraphQL.buildSchemaSync method to check if generated file works correctly.

We're using ts-node tmp-file.ts --compiler-options [options] to perform the check under the hood.

Checker.Options

Writer

Writer will format generated source file.

Writer.options