【问题标题】:Adding a field resolver for a second api call with type-graphql and the RESTDataSource使用 type-graphql 和 RESTDataSource 为第二个 api 调用添加字段解析器
【发布时间】:2021-03-09 08:58:20
【问题描述】:

我们希望下面的查询根据返回的truckId 解析truck 字段:

实体

// RosterEntity.ts
import { Truck } from '@sap-truck-roster/entity/Truck'
import { Field, ID, ObjectType } from 'type-graphql'

@ObjectType()
export class Roster {
  @Field(() => Truck, { nullable: true })
  truck: Truck
  
  @Field(() => ID)
  readonly truckId: string
}
// TruckEntity.ts
import { Field, ID, ObjectType } from 'type-graphql'

@ObjectType()
export class Truck {
  @Field(() => ID)
  readonly id: string

  @Field()
  readonly description: string
}

解析器

// TruckResolver.ts
import { Resolver, Arg, Query, Ctx, Field, ObjectType, createUnionType,} from 'type-graphql'
import { Truck } from '@sap-truck-roster/entity/Truck'
import { plainToClass } from 'class-transformer'
import { Context } from '@shared/typings'
import { ApiError } from '@shared/graphql'

@ObjectType()
class TruckArray {
  @Field(() => [Truck], { nullable: true })
  data?: [Truck]
}

const TruckQueryResultUnion = createUnionType({
  name: 'TruckQueryResult',
  // types: () => [[Truck], ApiError] as const,
  // an array is not supported by the Graphql spec in unions
  types: () => [TruckArray, ApiError] as const,
})

@Resolver(() => Truck)
export class TruckResolver {
  @Query(() => TruckQueryResultUnion)
  async truck(
    @Ctx() ctx: Context,
    @Arg('id', { nullable: true }) id?: string,
    @Arg('country', { nullable: true }) country?: string
  ): Promise<typeof TruckQueryResultUnion> {
      const response = await ctx.dataSources.sapTruckRosterAPI.getTruck({ id, country })

      return plainToClass(TruckArray, { data: response.data, })
  }
}
// RosterResolver.ts
import { Resolver, Arg, Query, Ctx, Field, ObjectType, createUnionType,} from 'type-graphql'
import { Roster } from '@sap-truck-roster/entity/Roster'
import { plainToClass } from 'class-transformer'
import { Context } from '@shared/typings'
import { ApiError } from '@shared/graphql'
import { Truck } from '@sap-truck-roster/entity/Truck'

@ObjectType()
class RosterArray {
  @Field(() => [Roster], { nullable: true })
  data?: [Roster]
}

const RosterQueryResultUnion = createUnionType({
  name: 'RosterQueryResult',
  // types: () => [[Roster], ApiError] as const,
  // an array is not supported by the Graphql spec in unions
  types: () => [RosterArray, ApiError] as const,
})

@Resolver(() => Roster)
export class RosterResolver {
  @Query(() => RosterQueryResultUnion)
  async roster(
    @Ctx() ctx: Context,
    @Arg('date', () => String) date: string,
    @Arg('truckId', { nullable: true }) truckId?: string,
    @Arg('driverId', { nullable: true }) driverId?: string
  ): Promise<typeof RosterQueryResultUnion> {
      const response = await ctx.dataSources.sapTruckRosterAPI.getRoster({ date, driverId, truckId })

      // @FieldResolver(() => Truck)
      // truck(@Root() truck: Truck) {
      //   return await ctx.dataSources.sapTruckRosterAPI.getTruck({
      //     id: response.truckId
      //   })
      // }
      
     return plainToClass(RosterArray, { data: response.data })
  }
}

正如您在RosterResolver.ts 中看到的,我们尝试使用response.truckId 来查询API 上的另一个端点,但失败了。用数据填充 truck 字段的正确方法是什么?

这会在控制台中返回正确的数据,但与 roster 不匹配,因为我们获得了所有 truck 属性的 null 值:

  // RosterResolver.ts

  @FieldResolver(() => Truck, { nullable: true })
  async truck(@Root() roster: Roster, @Ctx() ctx: Context) {
    console.log('roster.truckId: ', roster.truckId)

    const response = await ctx.dataSources.sapTruckRosterAPI.getTruck({
      id: roster.truckId,
    })

    console.log('response: ', response);
    
    return response
  }

【问题讨论】:

    标签: graphql apollo-server typegraphql


    【解决方案1】:

    您可以做的是解析器继承。 https://github.com/MichalLytek/type-graphql/blob/master/docs/resolvers.md#field-resolvers

    @Resolver(() => Roster)
    export class RosterResolver {
    
      ....
    
      @FieldResolver()
      truck(@Root() roster: Roster) {
        return ctx.dataSources.sapTruckRosterAPI.getTruck({
          id: roster.truckId
        });
      }
    

    【讨论】:

    • 谢谢你的建议,但我试过了,但它失败了,“不能为不可为空的字段 Truck.id 返回 null。”。即使这样做@FieldResolver(() =&gt; Truck, { nullable: true })
    • 当我尝试 @FieldResolver(() =&gt; Roster, { nullable: true }) 时,我收到错误“无法在类型 \"Roster\" 上查询字段 \"id\"
    猜你喜欢
    • 2020-04-28
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 2020-07-28
    • 2017-06-03
    • 2019-12-18
    • 2021-02-08
    • 2020-08-31
    相关资源
    最近更新 更多