javascript - วิธีการกำหนดประเภทสำหรับบริบทของตัวแก้ไข Apollo?
ฉันมี subgraph ของ Apollo GraphQL แบบง่าย ๆ ซึ่งฉันต้องการกำหนดประเภทสำหรับอาร์กิวเมนต์ context ในตัวแก้ปัญหาของฉัน
ฉันสร้างตัวแก้ไขปัญหาและตั้งค่าประเภทสำหรับบริบทดังนี้:
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)
ฉันจะตั้งค่าประเภทบริบทสำหรับตัวแก้ปัญหา (resolver) ของฉันได้อย่างไร เพื่อให้ฉันสามารถเข้าถึงอินเทอร์เฟซและแหล่งข้อมูลต่างๆ เป็นต้น?
คำตอบ #1
โอเค ฉันคิดว่าฉันเจอวิธีแก้ปัญหาที่ดีกว่าแล้ว
สิ่งแรกก่อน เรามาเข้าใจจริงๆ ว่า buildSubgraphSchema สามารถรับอะไรได้บ้าง:
buildSubgraphSchema(
modulesOrSDL:
| (GraphQLSchemaModule | DocumentNode)[] //interesting...
| DocumentNode
| LegacySchemaModule, //our tried and true way
): GraphQLSchema
ปัญหาคือเรากำลังพยายามส่งค่า LegacySchemaModule ({typeDefs, resolvers}) แต่เนื่องจาก <unknown> generic ที่ถูกส่งเข้าไปใน GraphQLResovlerMap ทำให้เกิดความขัดแย้งกับ Context ที่กำหนดไว้อย่างชัดเจน
type LegacySchemaModule = {
typeDefs: DocumentNode | DocumentNode[];
resolvers?: GraphQLResolverMap<unknown>; //note `unknown`, the root of our typing errors
};
สิ่งที่เราจำเป็นต้องใช้ในการดำเนินการตามบริบทภายใน resolver จริงๆ คือ 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 และเซิร์ฟเวอร์เริ่มทำงานได้ดี แต่อย่างไรก็ตาม เปิดรับข้อเสนอแนะจากชุมชนเกี่ยวกับรูปแบบที่ดีกว่าในที่นี้
ในท้ายที่สุดฉันคิดว่าเครื่องมือสร้างโค้ดถูกออกแบบมาเพื่อแก้ไขปัญหาเหล่านี้มากมาย ตอนนี้ฉันกำลังเข้าไปสำรวจเรื่องนี้: https://the-guild.dev/graphql/codegen
สนุกนะ!
คำตอบ #2
คลาส ApolloServer เป็นแบบทั่วไป คุณควรกำหนดบริบทที่กำหนดเองของคุณเป็นพารามิเตอร์ชนิด ดูเอกสารและยูนิตเทสต์เหล่านี้
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()
})
});
