View

 

추석연휴 포함해서 약 2주일동안 정말 삽질을 많이 한 것 같다.

사실 아직 파야할 곳이 많아 막막하지만 그래도 물꼬가 트여서 써본다.

 

삽질 포인트는 아래와 같다.

1. Apollo Client와 Apollo Server는 둘다 있어야 되는건가? -> Yes

2. NextJs는 Server Render 방식인데, Server에 Apollo Server 설정을 할 수 있나? -> Yes

3. Typescript, NextJs, Apollo Server/Client을 모두 한 프로젝트에서 사용할 수 있나? -> Yes

 

1번 포인트에서 많이 헷갈렸던게 나는 Apollo Client가 Query을 실행하면 쿼리로 요청한 값만 전달되어 서버측 Model VO에서 해당부분만 값이 셋팅할거라고 생각했다. 그래서 Apollo Server는 필요없다고 판단했는데, 공식 사이트를 열심히 독해하면서 생각해보니

아예 GraphQL은 별도의 프로토콜로 통신하는 것 같았다. 설령 Apollo Server 없이 바로 API에서 받을 수 있다고 해도 Method는 Get, Post 따위가 아닌 GraphQL일 가능성도 있다. (이 부분은 테스트를 해보고 좀 더 스터디가 필요하다. 정말 Server가 필요한지!)

 

2번 포인트는 한 일주일 정도 다양하게 테스트를 해봤다.

GraphQL을 처리하는 서버는 아예 별개로 두고 NextJS 내에 API 서버와 React을 두는 방안,

GraphQL을 새로운 서버리스로 만들고 API랑 연동하는 방안,

GraphQL을 API 서버처럼 사용하는 방안 등등 시행착오를 격었다.

구글에 NextJS + Apollo Server 조합을 찾아보면 대부분 express을 통해 새로운 서버리스를 만든다.

그런데 내가 원했던건 NextJS 자체 한 통에서 한 포트로 프론트엔드-백엔드를 관리하는 거였다.

이렇게 한 통으로 관리가 안되면 NextJS을 사용하는 이유가 없다고 생각한다.

Apollo는 꽤 다양한 서버 구성이 가능했다. 그 중 나는 <React> - <GraphQL> - <DB> 구성으로 결정했다.

Redux처럼 충분히 데이터를 조합할 수 있는 구조라고 판단했다.

Beter 프로젝트는 상대적으로 해야되는 요건이 적어 가능할 것 같긴 한데 API을 구성하는 방안은 좀 더 연구를 해봐야 될 것 같다.

 

결과적으로 3번 포인트까지 테스트를 완료했다. 다행히 별도의 서버가 없어도 NextJS 안에서 모두 해결이 가능했다.

아래에는 내가 했던 셋팅 순서대로 정리해봤다.

 

1. NextJS로 프로젝트 생성하고 실행해보기

npx create-next-app <프로젝트 명>
cd <프로젝트 명>
rm yarn.lock
yarn -- 노파심에 한번더
yarn dev

 

2. 필요한 모듈 설치하기

  • @apollo/client
  • @apollo/react-hooks
  • @nexus/schema
  • apollo-server-micro
  • graphql
  • typescript
  • @types/node
  • @types/react

3. Typescript 설정하기

<프로젝트명>/pages/index.js -> index.tsx
<프로젝트명>/pages/_app.js -> _app.tsx
touch tsconfig.json
yarn build

여기까지 진행하고 브라우저에서 localhost:3000로 접속하면 NextJS(index.tsx) 웰컴 페이지가 나온다.

 

4. Apollo Server 스키마 만들기

  • @nexus/schema 모듈로 Graphql Object Type과 Query, Mutataion 정의
  • Query, Mutataion에 기재하는 type은 User처럼 정의해 놓은 타입
  • Query, Mutataion에는 resolve을 통해 반환되는 값을 전달 (여기서 Redux처럼 데이터를 정제하거나 DB 작업 진행)
  • makeSchema로 만들어 놓은 타입들 모아모아 스키마로 만들기
  • Apollo Server에서 만들어 놓은 스키마로 연동되도록 파라미터 넣어주기
  • handler config에 bodyParse은 disable하기 (-> 아마도 Request 내용을 parsing 하면 안되기 때문일 것 같음)
  • pages/ 경로 아래에 생성한 파일은 url로 호출이 되기 때문에 components는 src 폴더를 생성해 만들었다.
# /pages/api/graphql.ts

import { ApolloServer } from 'apollo-server-micro'
import { makeSchema, objectType, stringArg } from '@nexus/schema'

const User = objectType({
  name: 'User',
  definition(t) {
    t.string('id')
    t.string('email')
    t.string('name')
  }
})

const Query = objectType({
  name: 'Query',
  definition(t) {
    t.list.field('user', {
      type: 'User',
      resolve: (_, args) => {
        return [
          {
            id: 'abc1',
            name: 'ABC1',
            email: 'abc1@naver.com'
          },
          {
            id: 'abc2',
            name: 'ABC2',
            email: 'abc2@naver.com'
          },
          {
            id: 'abc3',
            name: 'ABC3',
            email: 'abc3@naver.com'
          }
        ]
      }
    })
  }
})

const schema = makeSchema({
  types: [
    Query,
    User
  ]
})

const server = new ApolloServer({ schema })

const handler = server.createHandler({ path: '/api/graphql' })

export const config = {
  api: {
    bodyParser: false
  }
}

export default handler

 

5. Apollo Client

  • Apollo Client 캐시, Apollo Server Uri 지정해서 생성
  • ApolloProvider로 Client 최상위에서 다른 컨포넌트로 상속
  • 컴포넌트에서는 @apollo/client gql로 플레이그라운드에서 호출하는 것 처럼 작성해 useQuery, useMutataion Hook 사용하여 화면에 전달받은 내용 표시
# /pages/_app.tsx

import type { AppProps } from 'next/app'
import '../styles/globals.css'

function MyApp ({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

export default MyApp
# /pages/index.ts

import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'
import { UserList } from '../src/components'

const Home = () => {
  const client = new ApolloClient({
    uri: 'http://localhost:3000/api/graphql',
    cache: new InMemoryCache()
  })

  return (
    <ApolloProvider client={client}>
      <div>
        <UserList />
      </div>
    </ApolloProvider>
  )
}
export default Home
# /src/components/UserList.tsx

import { useQuery } from "@apollo/react-hooks" 
import { useState } from "react"
import { gql } from "@apollo/client"

const Q_USERLIST = gql`
  query {
    user {
      id
      email
      name
    }
  }
`

function UserList () {
  const { loading, error, data } = useQuery(Q_USERLIST)
  const users = data ? data.user : []

  return (
    <div>
      {users && users.map(user => <div key={user.id}>{user.name}({user.email})</div>)}
    </div>
  )
}

export default UserList
# /src/components/index.ts

export { default as UserList } from './UserList'

 

막 시작할때는 어려웠는데 한번 해보고, 블로그 포스팅을 위해 다시 복습해보니 설정이 쉬운 것 같다.

아무리 봐도 신기한 GraphQL,,

'develop > react' 카테고리의 다른 글

Material-UI html2canvas SVG 안나오는 문제  (0) 2021.01.14
#5 Apollo 환경에 Prisma 끼얹기  (0) 2020.11.10
#3 NextJS에 PostgreSQL 연동하기  (0) 2020.09.25
#2 NextJS 기본 사용법  (0) 2020.09.25
React, Redux 개념 교육  (0) 2020.09.23
Share Link
reply
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31