node.js - چگونه متد isTypeOf را پیادهسازی کنیم؟
با توجه به این طرحواره:
interface INode {
id: ID
}
type Todo implements INode {
id: ID
title: String!
}
type Query {
node(id: ID!): INode
}
با توجه به این کلاس:
export default class Todo {
constructor (public id: string, public title: string) { }
isTypeOf(value: any): Boolean {
return value instanceof Todo;
}
}
با توجه به این مفسر:
type NodeArgs = {
id: string
}
export const resolver = {
node: ({ id }: NodeArgs) => {
return new Todo('1', 'Todo 1');
}
}
وقتی که من پرسوجو را فراخوانی میکنم:
query {
node(id: "1") {
id
... on Todo {
title
}
}
}
سپس خروجی زیر را دریافت میکنم:
{
"errors": [
{
"message": "Abstract type INode must resolve to an Object type at runtime for field Query.node with value { id: \"1\", title: \"Todo 1\" }, received \"undefined\". Either the INode type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"node"
]
}
],
"data": {
"node": null
}
}
همانطور که میبینید، من تابع isTypeOf را پیادهسازی کردهام اما هنوز هم پیام خطا دریافت میکنم.
من کجا اشتباه میکنم؟
یادداشتها :
- من از تایپاسکریپت، اکسپرس و اکسپرس-گرافکیوال استفاده میکنم؛
پاسخ شماره ۱
تابع isTypeOf تابعی است که هنگام ایجاد اسکیمای خود بهصورت برنامهنویسی شده، به سازندهی GraphQLObjectType منتقل میشود. همینطور برای توابع resolveType و اتحادها/رابطها صادق است. اگر از SDL استفاده کنید و اسکیمای خود را با buildSchema ایجاد کنید، هیچ راهی برای وارد کردن این توابع به اسکیمای ایجاد شده نخواهید داشت، درست همانطور که راهی برای ارائه resolver برای فیلدهای انواع غیر از Query و Mutation ندارید.
شما چند گزینه دارید. یک گزینه استفاده از رفتار پیشفرض resolveType است. این رفتار به دنبال یک ویژگی __typename در شیء میگردد و در صورت عدم یافتن، به فراخوانی isTypeOf بر روی هر نوع پیادهسازی ادامه میدهد تا مطابقت پیدا کند. این بدان معناست که اگر از یک کلاس استفاده میکنید، باید کافی باشد که چیزی شبیه این انجام دهید:
export default class Todo {
get __typename() {
return 'Todo'
}
}
گزینه بهتر این است که buildSchema را کنار بگذارید و از makeExecutableSchema در graphql-tools استفاده کنید. سپس میتوانید توابع resolveType و/یا isTypeOf خود را مستقیماً در حلکنندههای خود تعریف کنید. برای مثال:
const resolvers = {
Query: {
node: (obj, args, context, info) => {
return new Todo('1', 'Todo 1')
}
},
INode: {
__resolveType: (obj, context, info) => {
if (obj instanceof Todo) return 'Todo'
},
}
}
نه تنها میتوانید به راحتی isTypeOf یا resolveType را به این صورت تعریف کنید، بلکه میتوانید به راحتی رزولورها را برای فیلدهای هر نوع اضافه کرده و اسکالرهای سفارشی را بدون هیچ زحمتی اضافه کنید. اگر فقط از buildSchema استفاده کنید، نمیتوانید هیچکدام از این کارها را (به راحتی) انجام دهید.
ویرایش :
اگر ترجیح میدهید از isTypeOf به جای resolveType استفاده کنید، رزولورها چیزی شبیه به این خواهند بود:
const resolvers = {
Query: {
node: (obj, args, context, info) => {
return new Todo('1', 'Todo 1')
}
},
Todo: {
__isTypeOf: (obj, context, info) => {
return obj instanceof Todo
},
}
}
تنها یکی یا دیگری لازم است. یا برای هر نوع انتزاعی که استفاده میکنید، یک تابع resolveType بنویسید، یا برای هر نوع شیء که میتواند یک نوع انتزاعی باشد، یک تابع isTypeOf بنویسید.
