Node.js · 2026-04-14

서브스크립션과 실시간 알림: GraphQL 구현 요약

GraphQL Subscriptions을 사용해 Node.js 환경에서 실시간 알림을 구성하는 핵심 개념과 구현 예제, 확장 전략을 정리한 설명서

작성일 : 2026-04-14 ㆍ 작성자 : 관리자
post
목차

개요

실시간 기능은 사용자 경험을 한층 끌어올린다. GraphQL Subscriptions는 서버에서 클라이언트로 이벤트를 푸시하는 표준 방식이다. 이 글은 GraphQL Subscriptions를 Node.js 환경에서 구현하면서 고려할 점과 예제를 단계별로 설명한다. 초보자도 이해하기 쉽도록 핵심 개념을 먼저 정리한 뒤 코드 예제를 제공한다.

핵심 개념

Subscriptions는 클라이언트가 특정 이벤트 스트림에 연결하여 실시간으로 데이터를 받는 메커니즘이다. 일반적인 요청/응답 흐름과 달리 연결이 유지된다. 이를 위해 WebSocket 기반의 실시간 프로토콜이 주로 사용된다.

주요 요소

  • 스키마 정의: subscription 타입과 필드 선언
  • 퍼블리셔/구독자 패턴: 이벤트 발행과 구독자 알림
  • 실시간 통신: WebSocket 연결 관리
  • 스케일링: 여러 인스턴스 간 이벤트 전파

사전 준비

다음 환경을 가정한다.

  • Node.js 16+
  • Apollo Server 또는 비슷한 GraphQL 서버
  • graphql, graphql-subscriptions, graphql-ws 또는 subscriptions-transport-ws

이 글에서는 예제로 "GraphQL Subscriptions Node.js" 환경을 기준으로 설명하며, 실제 코드에서는 Apollo 기반 설정을 사용한다.

간단한 구현 흐름

작업 흐름은 다음과 같다.

  • 스키마에 subscription 타입 추가
  • 서버에서 PubSub(퍼브섭) 인스턴스 생성
  • 이벤트가 발생하면 publish 호출
  • 클라이언트가 subscription 쿼리로 실시간 데이터 수신

코드 예제

아래 예제는 Apollo Server와 graphql-ws를 이용한 기본 구성이다. 실제 서비스 환경에서는 인증과 스케일링 구성이 추가로 필요하다. 코드 블록은 JSX 형태의 문법을 포함할 경우 < 및 >로 변환했다.

서버 설정 (예제)

const { createServer } = require('http')
const { execute, subscribe } = require('graphql')
const { makeExecutableSchema } = require('@graphql-tools/schema')
const { useServer } = require('graphql-ws/lib/use/ws')
const { WebSocketServer } = require('ws')
const { ApolloServer } = require('apollo-server-express')
const express = require('express')
const { PubSub } = require('graphql-subscriptions')

const typeDefs = `
  type Message { id: ID!, content: String! }
  type Query { _: Boolean }
  type Mutation { sendMessage(content: String!): Message }
  type Subscription { messageSent: Message }
`

const pubsub = new PubSub()
const MESSAGE_TOPIC = 'MESSAGE_TOPIC'

const resolvers = {
  Query: {},
  Mutation: {
    sendMessage: (_, { content }) => {
      const msg = { id: Date.now().toString(), content }
      pubsub.publish(MESSAGE_TOPIC, { messageSent: msg })
      return msg
    }
  },
  Subscription: {
    messageSent: {
      subscribe: () => pubsub.asyncIterator([MESSAGE_TOPIC])
    }
  }
}

const schema = makeExecutableSchema({ typeDefs, resolvers })

async function start() {
  const app = express()
  const httpServer = createServer(app)

  const wsServer = new WebSocketServer({
    server: httpServer,
    path: '/graphql'
  })

  useServer({ schema, execute, subscribe }, wsServer)

  const server = new ApolloServer({ schema })
  await server.start()
  server.applyMiddleware({ app })

  httpServer.listen(4000, () => {
    console.log('Server ready at http://localhost:4000/graphql')
  })
}

start()

클라이언트 구독 예제

import { createClient } from 'graphql-ws'
import { subscribe, gql } from '@apollo/client'

const wsClient = createClient({ url: 'ws://localhost:4000/graphql' })

const SUBSCRIPTION = gql`subscription { messageSent { id content } }`

// pseudo-code for subscribing
wsClient.subscribe({ query: SUBSCRIPTION.loc.source.body }, {
  next: (data) => console.log('받은 메시지', data),
  error: (err) => console.error(err),
  complete: () => console.log('complete')
})

실무 팁과 주의사항

  • 인증: WebSocket 연결 시 토큰을 검증해야 한다. 연결 초기 단계의 컨텍스트에서 처리한다.
  • 에러 처리: 구독 중 발생한 예외를 적절히 클라이언트에 전달한다.
  • 리소스 관리: 많은 연결이 동시 유지되면 메모리와 소켓 한계에 도달할 수 있다.
  • 스케일링: 다중 인스턴스 환경에서는 Redis, NATS, Kafka 같은 중앙 퍼브섭을 사용해 이벤트를 전파한다.

확장과 운영

개발 단계에서는 in-memory PubSub가 편리하다. 그러나 프로덕션에서는 외부 메시지 브로커가 필요하다. 예를 들어 Redis를 사용하면 여러 서버 인스턴스가 동일한 토픽을 구독하고 이벤트를 공유할 수 있다. 이와 같은 전략은 "실시간 알림 GraphQL Node" 환경에서 높은 가용성을 확보하는 데 필수적이다.

결론

이 글에서는 GraphQL Subscriptions의 핵심 개념과 Node.js 환경에서의 기본 구현 방법을 다뤘다. 예제 코드는 Apollo와 graphql-ws 기반이며, 실제 서비스에서는 인증과 스케일링을 추가해야 한다. 또한, "Apollo subscriptions 예제"나 "GraphQL Subscriptions Node.js" 관련 검색어로 더 많은 실무 사례를 찾아볼 수 있다. 기본 흐름을 이해하면 실시간 알림 기능을 안정적으로 설계할 수 있다.

GraphQL Subscriptions Node.js Apollo subscriptions 예제 실시간 알림 GraphQL Node graphql-ws PubSub WebSocket Node.js 실시간 스케일링 Redis