Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

schema import types (or GraphQLSchema) from typescript #9932

Closed
MichaelRando opened this issue Apr 24, 2024 · 11 comments
Closed

schema import types (or GraphQLSchema) from typescript #9932

MichaelRando opened this issue Apr 24, 2024 · 11 comments
Assignees

Comments

@MichaelRando
Copy link

Which packages are impacted by your issue?

@graphql-codegen/cli, @graphql-codegen/core, @graphql-codegen/schema-ast, @graphql-codegen/typescript-operations, @graphql-codegen/typescript-resolvers, @graphql-codegen/typescript

Describe the bug

My failing example at https://github.com/MichaelRando/graphql-code-generator-test

I want to load schema from graphql. I want to customize enum with internal string substitution, otherwise I'm blocked on porting this api to codegen. I've followed the documentation to best my ability.

Your Example Website or App

https://github.com/MichaelRando/graphql-code-generator-test

Steps to Reproduce the Bug or Issue

sync the repo and try to generate via yarn codegen

Expected behavior

output files and internal representation enum are expected.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • NodeJS: 21.2
  • graphql version: 16.8
  • @graphql-codegen/* version(s):5.0.2

Codegen Config File

import type { CodegenConfig } from "@graphql-codegen/cli";
import { defineConfig } from "@eddeee888/gcg-typescript-resolver-files";

const config: CodegenConfig = {
schema: ["./moduleFile.ts", "./schemaFile.graphql"],
require: ["ts-node/register"],
generates: {
schema: {
...defineConfig(),
config: {
enumValues: {
Color: {
RED: "red",
GREEN: "green",
BLUE: "blue",
},
},
},
},
},
};

export default config;

Additional context

import {
GraphQLEnumType,
GraphQLObjectType,
GraphQLSchema,
GraphQLString,
} from "graphql";

const languageType = new GraphQLEnumType({
name: "ISOLanguage",
values: {
EN: {
value: "en",
},
ES: {
value: "es",
},
RU: {
value: "ru",
},
},
});
const userType = new GraphQLObjectType({
name: "User",
fields: {
id: { type: GraphQLString },
name: { type: GraphQLString },
language: { type: languageType },
},
});

// Define the Query type
const queryType = new GraphQLObjectType({
name: "Query",
fields: {
user: {
type: userType,
// args describes the arguments that the user query accepts
args: {
id: { type: GraphQLString },
},
resolve: (_, { id }) => {
return id;
},
},
},
});

const schema = new GraphQLSchema({
query: queryType,
});

export { schema };
export default schema;

@eddeee888
Copy link
Collaborator

Hello 👋

I've got a few questions about your setup:

  1. Do we need a mix of schema file, in both TypeScript and GraphQL? I'd migrate to one style. My personal preference is .graphql
  2. Could you help me understand what you mean by "I want to customize enum with internal string substitution," please?
  3. I think the server preset setup in codegen.ts is slightly off. If you'd like a GraphQL with server preset setup, you could take a look at this example: https://github.com/eddeee888/graphql-server-template

If you still see errors, please help provide specific expectation and errors you are seeing. 🙂

@eddeee888 eddeee888 self-assigned this Apr 27, 2024
@MichaelRando
Copy link
Author

MichaelRando commented Apr 27, 2024

  1. I don't know how to implement graphql enum internal values using SDL. All the examples are in code: https://learning.atheros.ai/blog/how-to-use-graphql-enum-type-and-its-best-practices

The enum class allows us to map enum values to internal values represented by integers (or different strings etc.). By defining enumerated values to an integer leads you to design your schema in the most efficient way in terms of performance.

  1. If you looking in my example; the enums work like typescript enums, rather than string constants. Some references for supporting this:
  1. Could you be more specific? Let me copy your codegen in and see what happens...
    same output I was getting:
✔ Parse Configuration
❯ Generate outputs
✔ Parse Configuration
⚠ Generate outputs
  ❯ Generate to schema
    ✔ Load GraphQL schemas
    ✔ Load GraphQL documents
    ✖ Location is invalid
Running lifecycle hook "afterStart" scripts...
[CLI] Loading Schemas
[CLI] Loading Documents
[CLI] Generating output
error Command failed with exit code 1.

Because this project is moving an existing api into a codegen one; I don't necessarily have the freedom to change it to meet needs. With graphql, changing types breaks signatures and clients error out, it's really brittle with respect to type values.

I'm trying both techniques to achieve the goal: typescript enum type definition as well as enumValues codegen config. The typescript stuff breaks easy, so that's this ticket at a minimum. The enumValues works in an empty project, but stops working in a nontrival context or when your server preset is used.

@eddeee888
Copy link
Collaborator

Thanks for the details, I think I understand now that you want to migrate enum in TypeScript to use SDL.

If that's the case, here's the steps I can recommend right now:

  1. Migrate all TypeScript to SDL. It'd look something like this:
type Query {
  colors: [Color]
  user(id: String): User
}

type User {
  id: String
  name: String
  language: ISOLanguage
}

enum ISOLanguage {
  EN
  ES
  RU
}

enum Color {
  RED
  GREEN
  BLUE
}
  1. Fix codegen setup. It'd look something like this:
import type { CodegenConfig } from "@graphql-codegen/cli";
import { defineConfig } from "@eddeee888/gcg-typescript-resolver-files";

const config: CodegenConfig = {
  schema: ["**/*.graphql"],
  require: ["ts-node/register"],
  generates: {
    "src/schema": defineConfig(),
  },
};

export default config;
  1. Follow the server preset guide to set up file structure:
src
  -- schema/
      -- base/
          -- schemaFile.graphql
  1. Run codegen

  2. Now, whenever you need to return language enum, you can. For example:

// src/schema/base/resolvers/User.ts

import type { UserResolvers } from "./../../types.generated";
export const User: UserResolvers = {
  /* Implement User resolver logic here */
  language: () => {
    return "EN"; // Can also be "ES", "RU"
  },
};

@MichaelRando
Copy link
Author

Your example does not appear to be type compatible with the codebase. We're not talking about typescript, we're talking about graphql. I have an existing codebase, it's SDL is a megabyte already. I cannot generate types compatible with the existing types. The existing type is:

const languageType = new GraphQLEnumType({
  name: "ISOLanguage",
  values: {
    EN: {
      value: "en",
    },
    ES: {
      value: "es",
    },
    RU: {
      value: "ru",
    },
  },
});

The reason it's incompatible is the internal representation is a mismatch between what you're doing, and what's needed for compatibility.

Please review my links again:

@MichaelRando
Copy link
Author

I found a codegen that "works", in that it accepts the parameters I'm passing

const config: CodegenConfig = {
  schema: files,
  generates: {
    schema: defineConfig({
      typesPluginsConfig: {
        enumValues: {
          ISOLanguage: {
            EN: "en",
            ES: "es",
            RU: "ru",
          },
        },
      },
    }),
  },
};

without server presets the codegen spits:

export enum IsoLanguage {
  En = 'en',
  Es = 'es',
  Ru = 'ru'
}

which compiles to javascript:

"use strict";
exports.__esModule = true;
exports.IsoLanguage = void 0;
var IsoLanguage;
(function (IsoLanguage) {
    IsoLanguage["En"] = "en";
    IsoLanguage["Es"] = "es";
    IsoLanguage["Ru"] = "ru";
})(IsoLanguage = exports.IsoLanguage || (exports.IsoLanguage = {}));

with the server preset and the enumValues it spits

export type ISOLanguage =
  | 'en'
  | 'es'
  | 'ru';

compiling both these down to javascript with tsc:

"use strict";
exports.__esModule = true;

I'm blocked until I can get the server preset to generate the code I'm looking for which transforms SDL uppercase to database lowercase.

@MichaelRando
Copy link
Author

typescript defined types (re: issue title) also seem to work when not defineConfig @eddeee888/gcg-typescript-resolver-files as a config, so I suspect the issues I'm having apply specifically to server presets; without which, the documented codegen stuff is working.

@eddeee888
Copy link
Collaborator

If you need to use TypeScript enum, you can set typesPluginsConfig.enumsAsTypes = false. e.g.

defineConfig({
      typesPluginsConfig: {
        enumsAsTypes: false,
        enumValues: {
          ISOLanguage: {
            EN: "en",
            ES: "es",
            RU: "ru",
          },
        },
      },
    })

@MichaelRando
Copy link
Author

Yup, I figured out that part; and changed the codegen repo to purely represent the fact that typescript schema don't work at all with server preset. In particular it early outs on

const sources = schemaAst.extensions.extendedSources;
        if (!Array.isArray(sources) || sources.length === 0) {
            throw new Error('Empty Sources. Make sure schema files are parsed correctly.');
        }

and so my existing typescript is not useful and has to be ported to SDL to work with the server config. I'm unblocked now, so that's good; but only allowing SDL schema definition should be documented, as I lost much time trying to get it to work. (And it's fine w/o the config preset in the way)

@eddeee888
Copy link
Collaborator

typescript schema don't work at all with server preset

Ah, gotcha, this is something I wasn't aware of. Thanks! I can look into improving the preset by adding this support.

Do you have other questions? Otherwise we can close this issue 🙂

@MichaelRando
Copy link
Author

no other questions, this issue is represented by "adding typescript support to preset". If that's tracked elsewhere, this is now done.

@eddeee888
Copy link
Collaborator

Thank you @MichaelRando , I have created an issue in Server Preset repo: eddeee888/graphql-code-generator-plugins#264

I'll look into adding support for your request in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants