Subscriptions

Subscriptions

Subscription은 Query 및 Mutationκ³Ό 같은 또 λ‹€λ₯Έ GraphQL μž‘μ—… μœ ν˜•μž…λ‹ˆλ‹€. μ–‘λ°©ν–₯ 전솑 계측, 주둜 μ›Ή μ†ŒμΌ“μ„ 톡해 μ‹€μ‹œκ°„ ꡬ독을 생성할 수 μžˆμŠ΅λ‹ˆλ‹€. Subscription에 λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ μ—¬κΈ°λ₯Ό μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€. μ•„λž˜λŠ” 곡식 Apollo λ¬Έμ„œμ—μ„œ 직접 볡사 ν•œ commentAdded ꡬ독 μ˜ˆμ œμž…λ‹ˆλ‹€.

Subscription: {
  commentAdded: {
    subscribe: () => pubSub.asyncIterator('commentAdded');
  }
}

warning μ•Œλ¦Ό pubsubλŠ” PubSub 클래슀의 μΈμŠ€ν„΄μŠ€μž…λ‹ˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ μ—¬κΈ°λ₯Ό μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€.

Schema first

Nestμ—μ„œ λ™λ“±ν•œ ꡬ독을 λ§Œλ“€λ €λ©΄ @Subscription()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

const pubSub = new PubSub();

@Resolver('Author')
export class AuthorResolver {
  constructor(
    private readonly authorsService: AuthorsService,
    private readonly postsService: PostsService,
  ) {}

  @Query('author')
  async getAuthor(@Args('id') id: number) {
    return await this.authorsService.findOneById(id);
  }

  @ResolveProperty('posts')
  async getPosts(@Parent() author) {
    const { id } = author;
    return await this.postsService.findAll({ authorId: id });
  }

  @Subscription()
  commentAdded() {
    return pubSub.asyncIterator('commentAdded');
  }
}

μ»¨ν…μŠ€νŠΈμ™€ 인수λ₯Ό 기반으둜 νŠΉμ • 이벀트λ₯Ό ν•„ν„°λ§ν•˜κΈ° μœ„ν•΄ filter속성을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@Subscription('commentAdded', {
  filter: (payload, variables) =>
    payload.commentAdded.repositoryName === variables.repoFullName,
})
commentAdded() {
  return pubSub.asyncIterator('commentAdded');
}

κ²Œμ‹œλœ νŽ˜μ΄λ‘œλ“œλ₯Ό λ³€κ²½ν•˜λ €λ©΄ resolve ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@Subscription('commentAdded', {
  resolve: value => value,
})
commentAdded() {
  return pubSub.asyncIterator('commentAdded');
}

Type definitions

λ§ˆμ§€λ§‰ λ‹¨κ³„λŠ” μœ ν˜• μ •μ˜ νŒŒμΌμ„ μ—…λ°μ΄νŠΈν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

type Author {
  id: Int!
  firstName: String
  lastName: String
  posts: [Post]
}

type Post {
  id: Int!
  title: String
  votes: Int
}

type Query {
  author(id: Int!): Author
}

type Comment {
  id: String
  content: String
}

type Subscription {
  commentAdded(repoFullName: String!): Comment
}

잘 ν–ˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” ν•˜λ‚˜μ˜ commentAdded(repoFullName: String!): Comment κ°€μž…μ„ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€. 전체 μƒ˜ν”Œ κ΅¬ν˜„μ€ μ—¬κΈ°μ—μ„œ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.

Code first

클래슀 μš°μ„  μ ‘κ·Ό 방식을 μ‚¬μš©ν•˜μ—¬ ꡬ독을 λ§Œλ“€λ €λ©΄ @Subscription() λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

const pubSub = new PubSub();

@Resolver('Author')
export class AuthorResolver {
  constructor(
    private readonly authorsService: AuthorsService,
    private readonly postsService: PostsService,
  ) {}

  @Query(returns => Author, { name: 'author' })
  async getAuthor(@Args({ name: 'id', type: () => Int }) id: number) {
    return await this.authorsService.findOneById(id);
  }

  @ResolveProperty('posts')
  async getPosts(@Parent() author) {
    const { id } = author;
    return await this.postsService.findAll({ authorId: id });
  }

  @Subscription(returns => Comment)
  commentAdded() {
    return pubSub.asyncIterator('commentAdded');
  }
}

μ»¨ν…μŠ€νŠΈμ™€ 인수λ₯Ό 기반으둜 νŠΉμ • 이벀트λ₯Ό ν•„ν„°λ§ν•˜κΈ° μœ„ν•΄ filter속성을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@Subscription(returns => Comment, {
  filter: (payload, variables) =>
    payload.commentAdded.repositoryName === variables.repoFullName,
})
commentAdded() {
  return pubSub.asyncIterator('commentAdded');
}

κ²Œμ‹œλœ νŽ˜μ΄λ‘œλ“œλ₯Ό λ³€κ²½ν•˜λ €λ©΄resolve ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@Subscription(returns => Comment, {
  resolve: value => value,
})
commentAdded() {
  return pubSub.asyncIterator('commentAdded');
}

PubSub

μ—¬κΈ°μ„œλŠ” 둜컬 PubSub μΈμŠ€ν„΄μŠ€λ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. λŒ€μ‹ , PubSubλ₯Ό κ³΅κΈ‰μžλ‘œ μ •μ˜ν•˜κ³  μƒμ„±μž (@inject()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬)λ₯Ό 톡해 μ£Όμž…ν•œ λ‹€μŒ 전체 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ 재 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. Nest μ‚¬μš©μž μ§€μ • κ³΅κΈ‰μž 여기에 λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ„ 읽을 수 μžˆμŠ΅λ‹ˆλ‹€.

{
  provide: 'PUB_SUB',
  useValue: new PubSub(),
}

Module

Subscription을 κ°€λŠ₯ν•˜κ²Œν•˜λ €λ©΄ installSubscriptionHandlers 속성을 true둜 μ„€μ •ν•΄μ•Όν•©λ‹ˆλ‹€.

GraphQLModule.forRoot({
  typePaths: ['./**/*.graphql'],
  installSubscriptionHandlers: true,
}),

Subscription μ„œλ²„ (예 : 포트 λ³€κ²½)λ₯Ό μ‚¬μš©μž μ •μ˜ν•˜λ €λ©΄ subscriptions 속성을 μ‚¬μš©ν•˜μ‹­μ‹œμ˜€ (μ—¬κΈ°).

Last updated

Was this helpful?