typescript-graphql-server icon indicating copy to clipboard operation
typescript-graphql-server copied to clipboard

Generate types for the "app" part

Open lucasavila00 opened this issue 6 years ago • 3 comments

I'm currently using graphql-code-generator to generate types for the "app" part of the code and the experience is awesome.

It gives me the types for the public api which I can export for the front-end and use on the server code itself. With these dependencies:

    "graphql-code-generator": "^0.9.1",
    "graphql-codegen-typescript-template": "^0.9.1",
    "graphql-import": "^0.6.0",

We need to join the schemas because of this kind of modular graphql schema used with prisma, so we create src/importSchema.ts

import { importSchema } from "graphql-import";
export default importSchema("./src/schema.graphql");

Automate it in prisma.yml:

hooks:
  post-deploy:
    - graphql get-schema --project database
    - graphql codegen
    - gql-gen --require ts-node/register --template typescript --export ./src/importSchema.ts --out ./src/typings/

or package.json

    "foo": "gql-gen --require ts-node/register --template typescript --export ./src/importSchema.ts --out ./src/typings/"

and we can use the types like so, in Query.ts (strict Typescript :+1: )

import { PostQueryArgs, Query } from "../typings/types";
// later...
  post(
    parent: never,
    { id }: PostQueryArgs, // type generated now
    ctx: Context,
    info: never
  ): Promise<Query["post"]> {
    return ctx.db.query.post({ where: { id: id } }, info);
  },

This approach should be added here, like this or with apollo-codegen (which I couldn't get to work like this). It helped me catch a bug on the prisma docs where they have a mutation like this on the app side:

type Mutation {
  createDraft(title: String!, content: String): Post
}

implemented like this

    createDraft(parent, { title, content }, ctx, info): Promise<Mutation["createDraft"]> {
      return ctx.db.mutation.createPost(
        {
          data: {
            title,
            content,
          },
        },
        info,
      )
    },

against a DB structured like this

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
}

So at app level "content" was optional. At DB level it wasn't. The typescript compiler wouldn't warn if I hadn't taken this approach. Also, in this project, if we remove a "!" from a type or argument at app level the compiler won't catch this regression unless we generate the types.

lucasavila00 avatar Jun 04 '18 03:06 lucasavila00

Would it work like this ?

in .graphqlconfig.yml

app:
    schemaPath: src/schema.graphql
    includes: ["**/*.graphql"]
    extensions:
      endpoints:
        default: ${env:API_PROTOCOL}://${env:API_HOST}:${env:API_PORT}
      codegen:
        - generator: prisma-binding
          language: typescript
          output:
            binding: src/generated/api.ts

then reference api-side types in resolvers with import { Query } from '../../generated/api';

Would not it be cleaner and less dependencies ?

Sharlaan avatar Jul 21 '18 12:07 Sharlaan

@Sharlaan, I'll surely give it a shot! I have been getting some issues when those implementations diverge on more complicated use-cases. Right now I have them forked on both sides to make it work on another project of mine.

lucasavila00 avatar Jul 25 '18 01:07 lucasavila00

@degroote22 nice help!

It looks like using the newest version of graphql-code-generator and graphql-codegen-typescript-template, you don't need graphql-import anymore

    "graphql-code-generator": "^0.11.0",
    "graphql-codegen-typescript-template": "^0.11.0",
gql-gen --require ts-node/register --template typescript -s ./src/schema.graphql --out ./src/typings/

rafaelugolini avatar Sep 01 '18 07:09 rafaelugolini