Skip to content

Traditional Codegen Workflow

cwstra edited this page Apr 15, 2024 · 10 revisions

Traditional Codegen Workflow

In this approach, a developer creates .graphql files. These files are recognized by the graphql-codegen cli, which then generates corresponding rescript output.

Installation

Prerequisite packages:

  • graphql
  • @graphql-codegen/cli
  • @graphql-codegen/near-operation-file-preset (this requirement might be swapped out for a custom preset in the future)

We provide two plugins particular to rescript:

  • @rescript-graphql-codegen/base-types: This generates GQL input objects and enums for the overall schema.
  • @rescript-graphql-codegen/operations: This generates query and mutation types for individual .graphql files.

To install all of these dependencies at once:

# npm
npm i graphql
npm i -D @graphql-codegen/cli @graphql-codegen/near-operation-file-preset @rescript-graphql-codegen/base-types @rescript-graphql-codegen/operations

# yarn
yarn add graphql
yarn add --dev @graphql-codegen/cli @graphql-codegen/near-operation-file-preset @rescript-graphql-codegen/base-types @rescript-graphql-codegen/operations

Example Configuration

codegen.ts

import type {CodegenConfig} from '@graphql-codegen/cli'

// Absolute name of your scalars module (described later)
const scalarModule = "GraphqlBase__Scalars";

const config: CodegenConfig = {
  // Path to GQL schema file
  schema: "src/Graphql/schema.graphql",
  generates: {
    // Entry to generate the base types file
    "src/GraphqlBase/GraphqlBase__Types.res": {
      plugins: ["@rescript-graphql-codegen/base-types"],
      config: {
        scalarModule
      }
    },
    // Entry for operations files
    "src/": {
      // Glob to all source files
      documents: "src/**/*.graphql",
      // Here we make use of a typescript preset that does _roughly_ what we want
      preset: "near-operation-file",
      presetConfig: {
        extension: ".res",
        // If baseTypesPath is anything other than '.', the preset will generate
        // typescript imports, which is bad news.
        baseTypesPath: ".",
        // Not required, but adding generated extensions doesn't really play nice
        // with rescript's module names; much easier to use folders as ignore targets.
        "folder": "__generated__",
      },
      config: {
        // Module name of the generated base types file, as defined above.
        baseTypesModule: "GraphqlBase__Types",
        // Without this, the preset will generate typescript imports;
        // still not what we want.
        globalNamespace: true,
        scalarModule
      },
      plugins: [
        "@rescript-graphql-codegen/operations"
      ]
    }
  }
}

export default config

Scalars module

As seen in codegen.ts, the plugins expect a particular scalarsModule to be present in your application. This module should contain one submodule for each scalar defined in your server’s schema; each of these submodules must contain a type t, describing the runtime value of that scalar type.

This gives you some additional flexibility around using these types. For basic scalars, such as the built-in scalars, these modules can be very simple:

module Boolean = {
  type t = bool
}
module Float = {
  type t = float
}
module Id = {
  type t = string
}
module Int = {
  type t = int
}
module String = {
  type t = string
}

At the same time, we can customize the interface of more particular scalars. For example, if we have a Date type, encoded to a string, we can create an opaque type to ensure proper encoding and decoding:

module Date: {
  type t
  let toJsDate: t => Js.Date.t
  let fromJsDate: Js.Date.t => t
} = {
  type t = string
  let toJsDate = ...
  let fromJsDate = ...
}

The ever-helpful rescript compiler should point out any missing scalars as they appear in generated code.

Clone this wiki locally