NodeJS 如何设置Apollo解析器上下文的类型?

iovurdzv  于 2023-02-03  发布在  Node.js
关注(0)|答案(3)|浏览(190)

我有一个简单的Apollo GraphQL子图,我想在解析器中为上下文参数设置类型。
我创建了一个冲突解决程序,并按如下方式设置上下文的类型:

interface Context {
  dataSources: {
    shopify: Shopify;
  }
}

const server = new ApolloServer({
  schema: buildSubgraphSchema({ 
    typeDefs,
    resolvers: {
      Query: {
        shop(_, _args, ctx: Context) {
          console.log("ctx:", ctx)
        },
      }
    }
  }),
  dataSources: () => ({
    shopify: new Shopify()
  })
});

但是,我设置的Context接口似乎与解析程序所需的类型不兼容,并得到以下错误:

Argument of type '{ typeDefs: any; resolvers: { Query: { shop(_: any, _args: any, ctx: Context): void; }; }; }' is not assignable to parameter of type 'DocumentNode | (GraphQLSchemaModule | DocumentNode)[] | LegacySchemaModule'.
  Types of property 'resolvers' are incompatible.
    Property 'Query' is incompatible with index signature.
      Type '{ shop(_: any, _args: any, ctx: Context): void; }' is not assignable to type 'GraphQLScalarType<unknown, unknown> | { [enumValue: string]: string | number; } | { [fieldName: string]: GraphQLFieldResolver<any, unknown, any, unknown> | { requires?: string | undefined; resolve: GraphQLFieldResolver<...>; }; }'.
        Types of property 'shop' are incompatible.
          Type '(_: any, _args: any, ctx: Context) => void' is not assignable to type 'string | number | GraphQLFieldResolver<any, unknown, any, unknown> | { requires?: string | undefined; resolve: GraphQLFieldResolver<any, unknown, any, unknown>; } | undefined'.
            Type '(_: any, _args: any, ctx: Context) => void' is not assignable to type 'GraphQLFieldResolver<any, unknown, any, unknown>'.
              Types of parameters 'ctx' and 'context' are incompatible.
                Type 'unknown' is not assignable to type 'Context'.ts(2345)

我如何为我的解析器设置上下文类型,以便我可以访问接口和数据源等?

1zmg4dgp

1zmg4dgp1#

好吧我想我找到了更好的解决办法。
首先,让我们真正了解buildSubgraphSchema可以接受什么:

buildSubgraphSchema(
  modulesOrSDL:
    | (GraphQLSchemaModule | DocumentNode)[] //interesting...
    | DocumentNode
    | LegacySchemaModule, //our tried and true way
): GraphQLSchema

问题是我们尝试传入LegacySchemaModule{typeDefs, resolvers}),但由于传入GraphQLResovlerMap<unknown>泛型与显式定义的Context产生冲突

type LegacySchemaModule = {
  typeDefs: DocumentNode | DocumentNode[];
  resolvers?: GraphQLResolverMap<unknown>; //note `unknown`, the root of our typing errors
};

我们需要在中使用GraphQLSchemaModule来实际操作解析器中的上下文,定义如下:

export interface GraphQLSchemaModule {
  typeDefs: DocumentNode;
  resolvers?: GraphQLResolverMap<any>; //note the `any` here
}

因此,使用如下定义的解析器:

export const resolvers: GraphQLResolverMap<Context> = {
  Query: {
    shop(_, _args, ctx) {
      console.log(ctx.datasources.shopify); // Shopify
    },
  },
};

现在我们可以传入一个(GraphQLSchemaModule | DocumentNode)[]数组:

const server = new ApolloServer({ 
    schema: buildSubgraphSchema([ //note the array
      {
        typeDefs, //DocumentNode
        resolvers, //GraphQLSchemaModule, in this case GraphQLResolverMap<Context>
      },
    ]),
  });

这对我很有效,没有TS错误,服务器启动得很好。欢迎社区提出更好的模式。
最终我认为codegen工具被设计来解决很多这样的问题。我现在就深入到这一点:https://the-guild.dev/graphql/codegen
好好玩!

ycl3bljg

ycl3bljg2#

ApolloServer类是泛型的,您应该将自定义上下文指定为类型参数。请参见the docsthese unit tests

interface Context {
  dataSources: {
    shopify: Shopify;
  }
}

const server = new ApolloServer<Context>({
//                             ^^^^^^^^^
  schema: buildSubgraphSchema({ 
    typeDefs,
    resolvers: {
      Query: {
        shop(_, _args, ctx: Context) {
          console.log("ctx:", ctx)
        },
      }
    }
  }),
  dataSources: () => ({
    shopify: new Shopify()
  })
});
pbgvytdp

pbgvytdp3#

ApolloServer类是泛型的,你应该把你的自定义上下文指定为类型参数。参见文档和这些单元测试。
我也是这么想的,但它还是把它看作是一个LegacySchemaModule和ts croaks......我上面较长的答案中的模式似乎是现在的做法?
我尝试了你的代码,但得到了相同的类型与unknownContext冲突:

error TS2345: Argument of type '{ typeDefs: DocumentNode; resolvers: { Query: { shop(_: any, _args: any, ctx: Context): void; }; }; }' is not assignable to parameter of type 'DocumentNode | (DocumentNode | GraphQLSchemaModule)[] | LegacySchemaModule'.
  Types of property 'resolvers' are incompatible.
    Property 'Query' is incompatible with index signature.
      Type '{ shop(_: any, _args: any, ctx: Context): void; }' is not assignable to type 'GraphQLScalarType<unknown, unknown> | { [enumValue: string]: string | number; } | { [fieldName: string]: GraphQLFieldResolver<any, unknown, any, unknown> | { requires?: string | undefined; resolve: GraphQLFieldResolver<...>; }; }'.
        Types of property 'shop' are incompatible.
          Type '(_: any, _args: any, ctx: Context) => void' is not assignable to type 'string | number | GraphQLFieldResolver<any, unknown, any, unknown> | { requires?: string | undefined; resolve: GraphQLFieldResolver<any, unknown, any, unknown>; } | undefined'.
            Type '(_: any, _args: any, ctx: Context) => void' is not assignable to type 'GraphQLFieldResolver<any, unknown, any, unknown>'.
              Types of parameters 'ctx' and 'context' are incompatible.
>>>>>>>>>      Type 'unknown' is not assignable to type 'Context'.  
                    ^^^^^^^^^ -- seems to originate in LegacySchemaModule because
                                 we are pssing in {typeDefs,resolvers} as an object

相关问题