hollowverse-archive / hollowverse

The new Hollowverse.com
The Unlicense
9 stars 4 forks source link

Consider using TypeGraphQL for the API codebase #570

Open forabi opened 6 years ago

forabi commented 6 years ago

There are few different ways of defining GraphQL schema and the executable resolvers:

  1. Define schema in GraphQL SDL and convert the types to TypeScript to get type-safe resolvers. This is the approach we are currently using. This works well as we can easily define the entire schema in a single file using a simple definition language and then enforce type safety based on the generated types. The downside to this approach is that we need to have a build step in which we convert the GraphQL SDL types to their equivalent TS types.
  2. Define the GraphQL types and the executable resolvers in TypeScript using the graphql package helper functions. The upside is that we don't need a build step. The downside to this approach: cannot inspect the entire schema easily, very verbose.
  3. Use TypeGraphQL to define the schema using TypeScript. This is similar to 2 but could be much less verbose because it uses decorators to annotate interfaces, and could possibly integrate with our TypeORM classes so we won't have to define separate interface types -- instead of having SDL types + generated TS types + TypeORM classes, it's possible that we will need only TypeORM classes with decorators. This might be a good or a bad thing because while this could simplify the codebase, we don't necessarily want our schema to be tightly coupled to our ORM layer. Another thing to consider is whether this library will be maintained actively in the future, compared to the extremely active Apollo + graphql-js community.
wholesomedev commented 6 years ago

Why is having a build step a problem? We have build steps for pretty much everything.

Does Apollo + graphql-js provide a solution to this problem? Why don't we use that?

forabi commented 6 years ago

Why is having a build step a problem? We have build steps for pretty much everything.

You're right. But this particular step does not work well in watch mode while I'm developing. I usually have to stop and restart the API server to have Webpack pick up the changes.

But there is another reason why I think (3) is a better option -- it's because the GraphQL SDL is pretty limited compared to TypeScript. For example, there are no generic types so you have to repeat a lot of types:


type NotablePersonEdge {
  cursor: ID!
  node: NotablePerson!
}

type NotablePersonConnection {
  edges: [NotablePersonEdge!]!
  pageInfo: PageInfo!
}

type UserEdge {
  cursor: ID!
  node: User!
}

type UserConnection {
  edges: [UserEdge!]!
  pageInfo: PageInfo!
}

As we add more connection types, the schema file will get very big.

On the other hand, this could much more concise in TypeScript:

type Edge<Node> = {
  cursor: string;
  node: Node;
};

type Connection<Node> = {
  edges: Edge<Node>[];
  pageInfo: PageInfo;
};

type UserConnection = Connection<User>;
type NotablePersonConnection = Connection<NotablePerson>;
forabi commented 6 years ago

Does Apollo + graphql-js provide a solution to this problem? Why don't we use that?

No, I don't think using graphql-js is a good option. Defining types requires tons of boilerplate.

wholesomedev commented 6 years ago

@forabi I'm okay with TypeGraphQL. If it turns out that it is not the best choice, we can refactor it out.

forabi commented 6 years ago

@wholesomedev I'm not saying that we should use it. I've just recently came across it and I thought it could be useful because it integrates with TS and TypeORM. We'll probably need to think about and experiment with this more.

wholesomedev commented 6 years ago

@forabi sounds good to me 😄