typescript-graphql-server
typescript-graphql-server copied to clipboard
Generate types for the "app" part
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.
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, 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.
@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/