33.Subscription(1)_server.js

김종민·2022년 4월 29일
0

insta-backend

목록 보기
34/37

backend에서 가장 어려운 부분, 중요한 부분, update가 자주 일어나는 부분.
고래도 할 수 있다!!!!!
항상, 공식문서를 참고할것.!!!

https://www.apollographql.com/docs/apollo-server/data/subscriptions/

https://www.apollographql.com/docs/apollo-server/data/subscriptions/#enabling-subscriptions

https://www.apollographql.com/docs/apollo-server/data/subscriptions/#onconnect-and-ondisconnect

1. server.js

npm install graphql-ws ws @graphql-tools/schema apollo-server-core

 require('dotenv').config()
import { ApolloServer } from 'apollo-server-express'
import { graphqlUploadExpress } from 'graphql-upload'
import { getUser } from './users/users.util'
import express from 'express'
import { createServer } from 'http'
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core'
import { WebSocketServer } from 'ws'
import { useServer } from 'graphql-ws/lib/use/ws'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { typeDefs, resolvers } from './schema'

const PORT = process.env.PORT

const startServer = async () => {
  const schema = makeExecutableSchema({ typeDefs, resolvers })

  const app = express()
  app.use(graphqlUploadExpress())
  app.use('/static', express.static('uploads'))

  const httpServer = createServer(app)
  const wsServer = new WebSocketServer({
    server: httpServer,
    path: '/graphql',
  })
  //우리가 naver해외축구 같은 페이지를 볼떄, 단방향 통신, 즉, 한번data가 오고,
  //다시 req가 있기 전까지 통신이 연결이 안되어 있는게 http 서버
  //채팅처럼 연결이 끝어지지않고 유지가 되는게 WebSock 서버임.
  // 맨처음, http서버와 wsServer를 만들어줌.
  
  ------------------------------
  // const getDynamicContext = async (ctx, msg, args) => {
  //   if (ctx.connectionParams.token) {
  //     console.log(ctx)
  //     const loggedInUser = await getUser(ctx.connectionParams.token)
  //     console.log(loggedInUser)
  //     return { loggedInUser }
  //   }
  // }
  --------------------------참고만 할 것!, 지워더 상관 없는 부분.

  const serverCleanup = useServer(
    {
      schema,
      ///schema를 담아주고,
      ///wsServer가 연결됬을때와 연결이 끊어 졌을때를 설정해줌.
      
      onConnect: async (ctx) => {
        // console.log(ctx.connectionParams.token)
        // console.log(context)
        if (!ctx.connectionParams.token) {
          throw new Error('You can not listen')
        }
        //연결되었을때, token이 없으면 error던짐.
        
        
        const loggedInUser = await getUser(ctx.connectionParams.token)
        // return loggedInUser
		//여기서 return 한 loggedInUser는 context로 감
        //기존에는 여기서 loggedInUser를 token으로 찾아서 return해 주면,
        //subscribe resolver의 context로 loggedInUser가 갔는데,
        //이제는 가지 않음.  밑의 context: ~ 방법으로 subscribe resolvers에
        //loggedInUser를 return함. context에~~
      },
      context: async (ctx) => {
        const loggedInUser = await getUser(ctx.connectionParams.token)
        return loggedInUser
      },
      ///subscribr resolvers(roomUpdates등등)의 context에 loggedInUser를 보냄
      
      onDisconnect(ctx, code, reason) {
        console.log('Disconnected!')
      },
    },
    wsServer
  )

  const server = new ApolloServer({
    schema,
    context: async (ctx) => {
      // console.log(ctx.req.headers.token)
      if (ctx.req) {
        return {
          loggedInUser: await getUser(ctx.req.headers.token),
        }
        ///subscribe resolvers가 아닌 일반 resolvers(http 사용)의
        ///context에 loggedInUser를 보냄
        //원래는 else 부분은 webSocket연결시 context에 loggendInUser를
        //보내는 방법인데 작동을 안함. else이후 부분은 없어도 됨.
        
      } else {
        const {
          connection: { context },
        } = ctx
        return {
          loggedInUser: context.loggedInUser,
        }
      }
    },
    
    //이후 부분은 공식문서를 따라한 것임.
    
    plugins: [
      ApolloServerPluginDrainHttpServer({ httpServer }),
      {
        async serverWillStart() {
          return {
            async drainServer() {
              await serverCleanup.dispose()
            },
          }
        },
      },
    ],
  })
  await server.start()
  server.applyMiddleware({ app })
  httpServer.listen(PORT, () => {
    console.log(
      `Server is now running on http://localhost:${PORT}${server.graphqlPath}`
    )
  })
}
startServer()

!!!check
이전( 몇달전??)까지는(2022.4.29기준) subscriptions-transport-ws를 사용해서
subscription을 구현했으나, (2022.4.29 기준) 현재는 graphql-ws 를 이용해서
subscription을 구현함.!!!!
개인적으로 backend에서 가장 어렵고 중요한 부분임...

profile
코딩하는초딩쌤

0개의 댓글