hayes / pothos

Pothos GraphQL is library for creating GraphQL schemas in typescript using a strongly typed code first approach
https://pothos-graphql.dev
ISC License
2.36k stars 164 forks source link

Setting `parent`, `context` and `pageInfo` types for relay plugin #1305

Open garfieldnate opened 2 months ago

garfieldnate commented 2 months ago

I'm investigating doing a migration to pothos for a fairly complex existing codebase. We use a custom PageInfo type for relay connections as well as custom Parent and Context types for resolver arguments. Here are our types:

import type { PageInfo } from "graphql-relay";
import { enums } from "globals";
import type { Knex } from "knex";

interface PageInfoWithCount extends PageInfo {
  totalCount?: number | null;
}

export interface ConnectionWithCount<T> extends Connection<T> {
  pageInfo: PageInfoWithCount;
}

interface GraphQLContext {
  myCustomField: string;
  dbConnection: Knex;
  // etc.
}

export interface ParentType {
  __nodeType__: string;
  __dbName__: DBNameType;
  [key: string]: any;
  id: Buffer | number;
}

The relay plugin documentation page lists a large number of options, but doesn't show any examples of using them. I see the following possibly relevant options:

Here's some follow-up code that tries to define a resolver using the above types:

import SchemaBuilder, { Resolver } from "@pothos/core";
import RelayPlugin from "@pothos/plugin-relay";

const builder = new SchemaBuilder({
  plugins: [RelayPlugin],
  relay: {
    idFieldName: "ID",
    // ??? not sure what else
  }
});
builder.queryType({
  fields: (t) => ({
    ID: t.globalID({
      // does not type-check
      resolve: (parent: ParentType, args, context: GraphQLContext, resolveInfo) => "foo",
    });
  })
});

The resolver does not type-check, failing with this error:

  Types of parameters 'parent' and 'parent' are incompatible.
    Type '{}' is missing the following properties from type 'ParentType': __nodeType__, __dbName__, id

I apologize if this is a very basic question! Any documentation pointers or tips here would be much appreciated.

hayes commented 2 months ago

There is a lot to unpack in this question, and touches a lot of different components.

In general, in Pothos you will almost never define types for your resolver manually. They should always be typed for you based on types provided elsewhere.

This is probably very different than your existing set up, but leads to much better type safety, and an easier developer experience once you get things set up, and understand the patterns being used.

Some of what you asked about isn't well documented, and currently requires some workarounds (mostly extending the pageInfo type to have a totalCount type)

Rather than trying to explain each piece individually, I tried to create a quick interactive demo that adds most of the pieces you asked about:

https://stackblitz.com/edit/typescript-wrj4wo?file=index.ts

garfieldnate commented 2 months ago

Wow, thank you for such a thorough and fast response!

It looks like Root and Connection in SchemaBuilder's types are not documented, and extending pageInfo is not directly supported, though certainly possible (thank you so much for figuring all of that out for me!). Not sure if these require follow-up tickets.

This gives me plenty to work with for a while. Thanks again!

hayes commented 2 months ago

Context is documented here: https://pothos-graphql.dev/docs/guide/context

Root is kind of obscure, it should probably be added to the API docs, but I've never actually seen it used in a real GraphQL API, and I am not entirely sure that it's supported in all the popular graphql server implementations.

Extending existing types is probably something that could be covered in the docs.

I did remember there was a less hacky solution (but also undocumented) to extend pageInfo:

builder.objectField(builder.pageInfoRef(), 'totalCount', ...)

This could probably be documented, and I think won't pick up the extended types from the builder, so would probably require a type cast in the resolver (which probably could also be fixed pretty easily)

PRs for docs are always appreciated if you see something that's missing!