iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
0
Modern Web

NestJs 讀書筆記系列 第 11

NestJs - GraphQL 內部結構說明 (Subscription篇)

  • 分享至 

  • xImage
  •  

Subscriptions

除了 Query 和 Mutation ,GraphQL 還提供第三種類型 Subscription。

Subscription 是一種將資料由 server 推向 clinet 的一種方式,而不是 clinet 發送請求後 server 回傳資料。

啟用 Subscription

將 installSubscriptionHandlers 設定為 true

GraphQLModule.forRoot({
  installSubscriptionHandlers: true,
})

Code first

NestJs Graphql 提供了 @Subscription decorator ,我們會將要使用此類型的函式加上 decorator
接著使用 graphql-subscriptions package 的 PubSub ,提供簡單的 publish(發布) 以及 subscribe(訂閱) 事件 API

  1. 調用 PubSub#asyncIterator 來訂閱事件。
    事件名稱:commentAdded
    我們有兩種方式可以定義事件方法:

    • 方法一:事件名稱與函式名稱是一樣的
    • 方法二:事件名稱與函式名稱可獨立命名

    Resolver Subscription

    //Path: src/authors/authors.resolver.ts
    import { Resolver, Query, ID, Args, Subscription, Mutation } from "@nestjs/graphql";
    import { PubSub } from 'graphql-subscriptions';
    
    import { AuthorsService } from './authors.service';
    import { Author } from './models/author.model';
    import { Comment } from './models/comment.model';
    
    const pubSub = new PubSub();
    
    @Resolver(of => Author)
    export class AuthorsResolver {
        ...
        // 方法一
        // @Subscription(returns => Comment)
        // commentAdded() {
        //     return pubSub.asyncIterator('commentAdded');
        // }
    
        // 方法二
        @Subscription(returns => Comment, {
            name: 'commentAdded',
        })
        addCommentHandler() {
            return pubSub.asyncIterator('commentAdded');
        }
    }
    

    Model

    // Path: src/authors/models/comment.model.ts
    
    @ObjectType()
    export class Comment {
        @Field({ nullable: true })
        comment?: string;
    }
    
  2. 調用 PubSub#publish 來發佈事件

    1. 在方法 publish 第一個參數放入事件名稱 ('commentAdded')
    2. 將事件的 payload 放到第二個參數,payload 格式必須符合 Subscription Schema。如果格式錯誤,訂閱將會失敗
      type Subscription {
        commentAdded: Comment!
      }
      

    Resolver Mutation

    import { Resolver, Query, ID, Args, Subscription, Mutation } from "@nestjs/graphql";
    import { PubSub } from 'graphql-subscriptions';
    
    import { AuthorsService } from './authors.service';
    import { Author } from './models/author.model';
    import { Comment } from './models/comment.model';
    
    const pubSub = new PubSub();
    
    @Resolver(of => Author)
    export class AuthorsResolver {
        ...
    
        @Mutation(returns => Comment) 
        addComment(@Args('comment', { type: () => String}) comment: string) {
            pubSub.publish('commentAdded',  { commentAdded: { comment } });
            return { comment };
        }
    
        ...
    }
    
  3. 啟動服務,打開 Playground 進行測試
    addComment API 發布事件
    subscription 監聽事件

    mutation {
      addComment(comment: "comment") {
        comment
      }
    }
    
    subscription {
      commentAdded {
        comment
      }
    }
    

    先讓 Subscription 進行監聽
    在未收到事件之前,它會一直轉圈圈,這很正常

    執行 Mutation addComment

    回到 Subscription commentAdded,能看到我們成功接收到事件的回傳值
    可以多發幾次事件請求,就能看到事件會一直往下增長
    對,他是往下,而且不能 scroll !!

Filtering subscriptions

想要過濾掉特定事件,可以使用 filter 屬性,它有兩個參數 payload, variables,最後回傳一個 boolean 值,決定是否會將事件發佈給前端監聽器。
payload 是由事件發送者傳過來的參數
variables 是訂閱者所接收到的參數

@Subscription(returns => Comment, {
    name: 'commentAdded',
    
    // 加入 filter 以及判斷式
    filter: (payload, variables) => {
        return payload.commentAdded.title === variables.title
    }
})

// 加入訂閱者參數
addCommentHandler(@Args('title') title: string) {
    return pubSub.asyncIterator('commentAdded');
}

接著到 playground 進行測試,發布者及訂閱者都多了 title 參數,在上面的判斷是中,我們設定兩者的 title 要一樣訂閱者才能成功接收到事件
讀者可以直接測試,當設定一樣的值,就能收到事件,反之,不一樣的值,subscription 就不會有任何反應
這樣我們就成功利用過濾器,過濾我們想要的事件

subscription mutation

官方還有 Sehema first 範例說明,由於只是 Schema 產生方式不太一樣,所以我這邊就不在多做說明

以上就是 Subscription 介紹!


上一篇
NestJs - GraphQL 內部結構說明 (下篇)
下一篇
NestJs - Hot Reload
系列文
NestJs 讀書筆記31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言