NestJs 延伸篇 - Federation 实作

上一篇我们建立了 gateway ,也把 Task Service 安装了 federation 的 dependency
接着我们建立 User Service 和 Message Service,也都需要安装 federation
之後在 User Service 写一个 Create User 的 API

root
 ├── services
 │    ├── task     (port: 4002)
 │    ├── user     (port: 4001)
 │    └── message  (port: 4003)
 └── gateway       (port: 4000)

根据之前的情境
一个 Task 会由一个 User 所建立
一个 User 可以有多的 Task

Task 必须与 User 有所关联,所以我们在 Task 中会新增一个 UserId 的栏位

User Service

使用 @key(fields: "_id") directive 设定 User 要接收什麽栏位,这边以 _id 为例子

Code first

在 model 中使用 @Directive 设定

@Directive(`@key(fields: "_id")`)
export class User extends Document {
    @Field(() => ID)
    _id: string;
}

Schema first

type User @key(fields: "_id") {
  _id: ID!
  name: String!
}

在 resolver 中还有另一个方法 resolveReference ,当有相关的资源要使用 User 的实体时,Apollo Gateway 便能使用它
注意的是要在 resolveReference 加上 @ResolveReference decorator

@ResolveReference()
resolveReference(reference: { __typename: string; _id: string }) {
    return this.usersService.findById(reference._id);
}

Task Service

使用 extend 来标记 User

Code first

在 Task 中新增一个 user 的 model ,指定要 extend 的栏位

@Directive('@extends')
@Directive(`@key(fields: "_id")`)
@ObjectType()
export class User {
  @Directive('@external')
  @Field(() => ID)
  _id: string;
}

Schema first

extend type User @key(fields: "id") {
  id: ID! @external
}

Resolver

接着在 Resolver 中写一个解析栏位物件的一个方法

@ResolveField(() => User)
user(@Parent() task: Task) {
  return { __typename: 'User', _id: task.userId };
}

以上我们就完成了在 gateway 中能利用 Task 的 userId ,到 User Service 中查询 User 并回传给 Task Service ,最终根据 Schema 的格式回传给 Client side

测试

:::warning
在开始测试前,请读者先将之前的资料先全部清除,之前的 Task 并没有 userId 的栏位,所以无法查出 User 物件
:::

我们直接在 http://localhost:4000/graphql gateway 上做测试

先建立一个 User

mutation {
  createUser(userData: { name: "JavaScript" }) {
    _id
    name
  }
}

接着建立 Task
这边与之前不一样得部分是多了一个 userId ,如果刚刚的 User 回传的 _id 没有纪录,请读者到资料库去找一下吧!
回传时,我们也能取得 User 的物件

mutation {
  createTask(taskData: { 
    title: "THE THING TO DO TODAY",
    content: "THE THING Content"
    userId: "5f840e6de88fe979392f010c"
  }) {
    _id
    title
    content
    user {
      name
      _id
    }
  }
}

最後使用查询找出刚刚建立的 Task

query {
  todoTasks {
    tasks {
      user {
        name
        _id
      }
      content
      title
    }
  }
}

完美!!!!/images/emoticon/emoticon07.gif


<<:  30天完成家庭任务平台:第二十七天

>>:  JavaScript 之旅 (27):Promise.any() & AggregateError

Day 26 - State Monad I

还记得先前提到 Math.random 并非是纯函式吗,因为每次给定相同的输入都会是不同的输出回传回...

Explain详解(优化查询好帮手)-Part2(possible_keys、key、key_len、ref、rows、filtered、Extra、Json格式的执行计画)

此篇为前篇的延续唷! 方便阅读再贴一次基本的explain及测试表 mysql> explai...

Day 12 Component Lifecycle -1

第十二天罗~ 当更新画面 我们必须触发 React 的更新流程, 这样最新的资料才会显示在画面上, ...

D23 - 走!去浏览器用 create & append 加餐

前言 恭喜 codepen 复活 \(^∀^)メ(^∀^)ノ 终於可以透过实作来学习如何选取元素、操...

[ 卡卡 DAY 4 ] - React Native 专案结构

我的资料结构 . ├── App.js // App root component,the star...