GraphQL React + Apollo Tutorial - 2. 시작하기

cadenzah·2020년 2월 17일
8
post-thumbnail

시작하기

이 튜토리얼은 프론트엔드를 다루므로, 백엔드를 구현하는 과정은 생략하는 대신 Node.js 튜토리얼에서 만든 서버를 사용하도록 하겠습니다.

React 어플리케이션을 모두 만들고 나면, 백엔드와 연동하기 위하여 필요한 코드를 삽입할 수 있게 됩니다.

참고: 이 튜토리얼로 완성한 프로젝트는 GitHub에서 확인할 수 있습니다. 본 튜토리얼 코스의 이어지는 장에서 만약 내용을 잘 따라오지 못하신다면, 얼마든지 링크를 참조하시며 활용하시기 바랍니다. 도한 각 코드 블록에는 대응하는 파일명이 함께 적혀있습니다. 해당 표기를 클릭하면 GitHub 상의 대응하는 파일로 바로 링크됩니다. 이를 참조하면 코드를 어디에 입력할지, 최종 결과물은 어떤 모습인지 등을 확실히 알 수 있습니다.

Frontend

어플리케이션 만들기

제일 먼저, React 프로젝트를 만들도록 하겠습니다! 첫 장에서 언급하였듯, create-react-app이 필요합니다.

아직 설치하지 않았다면, create-react-app을 Yarn을 사용하여 설치합니다.

yarn global add create-react-app

참고: 본 튜토리얼은 프로젝트 관리에 Yarn을 사용합니다. npm의 사용을 선호한다면, npm의 대응하는 명령어를 실행하셔도 됩니다.

이제, create-react-app을 사용하여 React 어플리케이션의 기본 구조를 구성할 수 있습니다.

create-react-app hackernews-react-apollo

이제 hackernews-react-apollo라고 하는 새로운 디렉토리가 생성되었을 겁니다. 이 안에는 기본적인 구성 설정이 들어있습니다.

지금까지 모든 것이 잘 작동하는지, 디렉토리 안으로 들어가 어플리케이션을 시작하여 확인합시다.

cd hackernews-react-apollo
yarn start

이제 브라우저가 자동으로 열리고, 어플리케이션이 실행되는 http://localhost:3000으로 접속하게 됩니다. 모든 것이 잘 되었다면, 아래와 같은 화면을 볼 수 있게 됩니다.

프로젝트 구조를 개선하려면, src 폴더 안에 다음 두 개의 디렉토리를 새롭게 생성하세요. 우선 components 디렉토리는 모든 React 컴포넌트를 포함합니다. 그리고 두번째 styles 디렉토리에는 이 프로젝트에서 사용할 모든 CSS 파일들을 포함합니다.

App.js는 컴포넌트이므로, components로 이동시킵니다. App.cssindex.css는 스타일을 포함하므로, styles로 이동시킵니다. 또한 각 .css파일을 참조하는 index.jsApp.js의 코드 내용을 수정해야 합니다.

($ .../hackernews-react-apollo/src/index.js)

import React from 'react'
import ReactDOM from 'react-dom'
import './styles/index.css'
import App from './components/App'    // 수정

($ .../hackernews-react-apollo/src/components/App.js)

import React, { Component } from 'react';
import logo from '../logo.svg';      // 수정
import '../styles/App.css';

이제 프로젝트 구조는 아래와 같이 바뀌었을 겁니다.

.
├── README.md
├── node_modules
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
├── src
│   ├── App.test.js
│   ├── components
│   │   └── App.js
│   ├── index.js
│   ├── logo.svg
│   ├── serviceWorker.js
│   └── styles
│       ├── App.css
│       └── index.css
└── yarn.lock

스타일 준비하기

이 튜토리얼은 GraphQL의 개념을 배우고, 이 개념을 React 어플리케이션에서 사용하는 방법을 배우는 것이 목표이므로, 스타일에는 들이는 시간을 최소화하겠습니다. 프로젝트에서 CSS의 사용을 최소화하도록, CSS 클래스들을 제공하는 Tachyons 라이브러리를 사용하겠습니다.

public/index.html 파일을 열어서 3번째 link 태그를 추가하고, Tachyons 라이브러리를 불러옵니다.
($ .../hackernews-react-apollo/public/index.html)

<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!-- 수정 --> <link rel="stylesheet" href="https://unpkg.com/tachyons@4.2.1/css/tachyons.min.css"/>

약간의 스타일을 새로 추가하는 것이 좋을 듯 합니다. 프로젝트에 사용할 스타일을 아래와 같이 추가합니다.

index.css 파일을 열고 아래의 내용으로 대체합니다.
($ .../hackernews-react-apollo/src/styles/index.css)

body {
  margin: 0;
  padding: 0;
  font-family: Verdana, Geneva, sans-serif;
}

input {
  max-width: 500px;
}

.gray {
  color: #828282;
}

.orange {
  background-color: #ff6600;
}

.background-gray {
  background-color: rgb(246,246,239);
}

.f11 {
  font-size: 11px;
}

.w85 {
  width: 85%;
}

.button {
  font-family: monospace;
  font-size: 10pt;
  color: black;
  background-color: buttonface;
  text-align: center;
  padding: 2px 6px 3px;
  border-width: 2px;
  border-style: outset;
  border-color: buttonface;
  cursor: pointer;
  max-width: 250px;
}

Apollo 클라이언트 설치하기

다음으로, Apollo 클라이언트와 Apollo의 React 바인딩을 설치해야 합니다. 몇 가지 패키지들로 이루어져 있습니다.
($ .../hackernews-react-apollo)

yarn add apollo-boost react-apollo graphql

설치한 패키지들에 대하여 간단히 알아보겠습니다.

  • apollo-boost는 Apollo 클라이언트를 다루는 데에 필요한 몇가지 패키지들을 한번에 설치해주는 편리한 모음 패키지입니다. 아래 패키지들을 포함합니다.
    • apollo-client: 모든 마술이 이루어지는 곳!
    • apollo-cache-inmemory: 추천하는 캐시 라이브러리
    • apollo-link-http: 원격 데이터 불러오기에 필요한 Apollo Link
    • apollo-link-error: 오류 처리를 위한 Apollo Link
    • apollo-link-state: 로컬 상태 관리를 위한 Apollo Link
    • graphql-tag: 쿼리와 뮤테이션에 사용될 gql 함수를 내보내줍니다
  • react-apollo는 Apollo 클라이언트를 React에서 사용하기 위한 바인딩을 제공합니다.
  • graphql은 Facebook이 작성한 GraphQL의 참조 구현입니다. Apollo 클라이언트는 여기에 포함된 기능들 중 일부를 사용하게 됩니다.

이제 됐습니다. 코드를 작성할 준비를 마쳤습니다! 🚀

ApolloClient 구성하기

Apollo는 모든 저수준 네트워크 로직들을 추상화하여 GraphQL 서버에 대한 인터페이스를 제공해줍니다. REST API들을 다룰 때와 달리, HTTP 요청을 구축하는 일을 더 이상 하지 않아도 됩니다. 그저 쿼리와 뮤테이션을 작성하고, ApolloClient 인스턴스를 사용하여 전송하기만 하면 됩니다.

Apollo를 사용할 때에 가장 먼저 할 일은 ApolloClient 인스턴스를 구성하는 것입니다. 그러려면 우선, 네트워크 연결을 형성할 수 있도록 GraphQL API 엔드포인트를 알아야 합니다.

src/index.js 파일을 열고, 아래의 내용으로 코드를 대체합니다.
($ .../hackernews-react-apollo/src/index.js)

import React from 'react'
import ReactDOM from 'react-dom'
import './styles/index.css'
import App from './components/App'
import * as serviceWorker from './serviceWorker';

// 1
import { ApolloProvider } from 'react-apollo'           // 수정
import { ApolloClient } from 'apollo-client'            // 수정
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'   // 수정


// 2
const httpLink = createHttpLink({                       // 수정
  uri: 'http://localhost:4000'                          // 수정
})                                                      // 수정

// 3
const client = new ApolloClient({
  link: httpLink,                                       // 수정
  cache: new InMemoryCache()                            // 수정
})

// 4
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
)
serviceWorker.unregister();

참고: create-react-app으로 생성된 프로젝트는 세미콜론(;)을 사용하고, String값을 표기할 때 큰 따옴표("")를 사용합니다. 여러분이 튜토리얼을 보며 추가하는 코드는 모두 세미콜론을 사용하지 않고, 대부분 작은 따옴표를 사용합니다. 기존에 이미 있었던 세미콜론을 지우거나, 큰따옴표를 작은 따옴표로 바꿔도 됩니다. 🔥

코드 주석에 적힌 번호들을 바탕으로 각각을 살펴보도록 하겠습니다.

  1. 설치한 패키지로부터 필수 의존성들을 불러옵니다.

  2. httpLink를 생성합니다. httpLink는 GraphQL API를 사용하여 ApolloClient 인스턴스에 연결합니다. GraphQL 서버는 http://localhost:4000에서 동작하고 있어야 합니다.

  3. 이제 httpLink를 인자로 전달하여 ApolloClient 인스턴스를 생성하고, InMemoryCache 인스턴스를 새로 생성합니다.

  4. 마지막으로 React 어플리케이션의 최상위 컴포넌트를 렌더링합니다. App은 고차 컴포넌트 ApolloProvider로 감싸지고, client를 props로 전달받습니다.

Backend

서버 코드 다운로드받기

앞서 언급한 대로, 이번 튜토리얼의 백엔드는 Node.js 튜토리얼에서 만든 최종 결과물을 그대로 가져와서 사용하겠습니다.

터미널에서 hackernews-react-apollo 디렉토리로 들어간 뒤 아래의 명령을 실행합니다.
($ .../hackernews-react-apollo)

curl https://codeload.github.com/howtographql/react-apollo/tar.gz/starter | tar -xz --strip=1 react-apollo-starter/server

참고: Windows를 사용하실 경우, Git CLI를 사용하면 curl과 같은 명령어에 따른 잠재적 문제를 방지할 수 있습니다.

이제 server 디렉토리가 프로젝트 폴더 내에 새로 생기고, 그 안에 백엔드 코드가 모두 들어있을 것입니다.

서버를 작동시키기 앞서, 주요 구성 요소들을 빠르게 살펴보겠습니다.

  • prisma: 이 디렉토리에는 Prisma 설정과 관련된 모든 파일들이 들어있습니다. Prisma 클라이언트는 GraphQL 리졸버 내에서 데이터베이스에 접근할 때 사용됩니다. ORM과 유사합니다.
    • prisma.yml는 Prisma 프로젝트의 최상위 구성 파일입니다.
    • datamodel.prisma는 GraphQL 스키마 정의 언어(Schema Definition Language; SDL)를 사용하여 데이터 모델을 정의합니다. Prisma를 사용하면, 데이터 모델은 데이터베이스의 스키마를 서술하는 데에 사용됩니다.
  • src: 이 디렉토리는 GraphQL 서버의 소스 파일을 가집니다.
    • schema.graphql어플리케이션 스키마를 포함합니다. 어플리케이션 스키마는 프론트엔드에서 보낼 수 있는 GraphQL 동작들을 정의합니다. 이 파일에 대하여 잠시 후에 자세히 살펴보도록 하겠습니다.
    • generated/prisma-client는 자동 생성된 Prisma 클라이언트를 포함합니다. 이 클라이언트는 데이터베이스 접근시 타입을 안전하게 검사합니다. ORM과 유사합니다.
    • resolvers에는 어플리케이션 스키마에서 정의된 동작에 따른 리졸버 함수들을 포함합니다.
    • index.js는 GraphQL 서버의 진입점입니다.

위에서 언급된 파일들 가운데, 프론트엔드 개발자인 당신과 관련있는 것은 server/src/schema.graphql에 정의된 어플리케이션 스키마 뿐입니다. 이 파일은 프론트엔드 어플리케이션에서 서버에 전송할 수 있는 모든 동작들(쿼리, 뮤테이션, 구독 등)을 정의하는 GraphQL 스키마를 포함합니다.

이 파일은 아래와 같은 모습을 보입니다.

($ .../hackernews-react-apollo/server/src/schema.graphql)

# import Link, Vote, LinkSubscriptionPayload, VoteSubscriptionPayload from "./generated/prisma.graphql"

type Query {
  feed(filter: String, skip: Int, first: Int, orderBy: LinkOrderByInput): Feed!
}

type Feed {
  links: [Link!]!
  count: Int!
}

type Mutation {
  post(url: String!, description: String!): Link!
  signup(email: String!, password: String!, name: String!): AuthPayload
  login(email: String!, password: String!): AuthPayload
  vote(linkId: ID!): Vote
}

type AuthPayload {
  token: String
  user: User
}

type User {
  id: ID!
  name: String!
  email: String!
}

type Subscription {
  newLink: LinkSubscriptionPayload
  newVote: VoteSubscriptionPayload
}

이 스키마는 아래와 같은 동작을 허용합니다.

  • Queries:
    • feed: 백엔드로부터 모든 링크들을 반환합니다. 참고로 이 쿼리는 필터링, 정렬, 페이지 매기기 기능을 위한 인자를 받을 수 있습니다.
  • Mutations:
    • post: 인증된 사용자가 새로운 링크를 생성합니다.
    • signup: 새로운 사용자를 위한 계정을 생성합니다.
    • login: 기존의 사용자가 로그인합니다.
    • vote: 인증된 사용자가 어떤 링크에 대하여 투표합니다.
  • Subscriptions
    • newLink: 새로운 링크가 생성되었을 때 실시간 갱신을 받습니다.
    • newVote: 새로운 투표가 이루어졌을 때 실시간 갱신을 받습니다.

예를 들어, 아래의 feed 쿼리를 전송하여, 서버로부터 첫 10개의 링크를 받을 수 있습니다.

{
  feed(skip: 0, first: 10) {
    links {
      description
      url
      postedBy {
        name
      }
    }
  }
}

또는, 아래의 signup 뮤테이션을 전송하여 새로운 사용자를 생성합니다.

mutation {
  signup(
    name: "Sarah",
    email: "sarah@graph.cool",
    password: "graphql"
  ) {
    token
    user {
      id
    }
  }
}

Prisma 데이터베이스 서비스 배포하기

서버를 시동하고 쿼리와 뮤테이션을 보내기에 앞서, 마지막으로 할 일이 하나 남았습니다. GraphQL 서버가 접근할 수 있도록 Prisma 프로젝트를 배포해야 합니다.

서비스를 배포하려면, 서버의 의존성을 모두 설치하고 server 디렉토리 내에서 prisma deploy 명령을 실행하기만 하면 됩니다.

터미널에서 server 디렉토리로 들어간 뒤 아래의 명령을 실행합니다.
($ .../hackernews-react-apollo/server)

cd server
yarn install
yarn prisma deploy

이미 prisma CLI를 전역 설치했다면(yarn global add prisma를 실행하면 됩니다) 위에서 yarn prisma deploy를 실행하지 않아도 됩니다. 이 경우, 대신 prisma deploy를 실행하면 됩니다.

서비스를 어디에 설정하고 배포할지 CLI가 물을 경우, 우선 Demo server를 선택해야 합니다. 이때 로그인이 필요하며, GitHub 계정으로 Prisma 계정을 생성할 수 있습니다. 다음으로 region을 선택하며, demo-us1 또는 demo-eu2 중에 선택하면 됩니다. 데모 서버는 AWS Aurora 데이터베이스의 무료 인스턴스를 제공합니다. 만약 Docker가 설치되어있다면, 로컬 PC에서 직접 배포하는 것도 가능합니다.

참고: 명령어 실행이 완료된 후, CLI는 Prisma API의 엔드포인트를 prisma.yml에 기록해줍니다. https://eu1.prisma.sh/john-doe/hackernews-node/dev와 같은 식의 값이 기록됩니다.

서버 둘러보기

Prisma 엔드포인트가 제대로 설정되었다면, 서버를 사용해보도록 합시다!

server 디렉토리로 들어간 뒤 아래의 명령을 실행하여 서버를 시동시킵니다.
($ .../hackernews-react-apollo/server)

yarn start

yarn startpackage.json에 정의된 start 스크립트를 실행합니다. 이 스크립트는 우선 서버를 시동하고(이 서버는 http://localhost:4000에서 실행됩니다), GraphQL Playground를 열어서 API를 다룰 수 있도록 해줍니다.

Playground는 "GraphQL IDE"로, 쿼리, 뮤테이션, 구독 등을 GraphQL API 서버에 전송할 수 있는 인터랙티브 환경을 제공합니다. REST API를 다룰 때에 사용하는 Postman과 유사한 도구이지만, 훨씬 더 장점이 많습니다.

Playground를 통하여 GraphQL API에 대한 내장 문서를 제공할 수 있습니다. 이 문서는 GraphQL 스키마를 기반으로 생성되는 것으로, Playground의 우측 하단에 위치한 초록색 SCHEMA 버튼을 누르면 열 수 있습니다. 결과적으로, 앞서 어플리케이션 스키마에서 볼 수 있었던 것과 동일한 정보를 볼 수 있습니다.

Playground의 좌측 패널은 쿼리, 뮤테이션, 구독 등을 작성할 수 있는 에디터 창입니다. 가운데의 재생 버튼을 클릭하면, 요청이 전송되고 서버의 응답이 우측의 결과 패널에 표시됩니다.

아래 2개의 뮤테이션을 에디터 패널에 복사합니다. 좌측 사이드 메뉴에서 app 프로젝트 내의 default Playground를 선택했는지 꼭 확인하세요.

mutation CreatePrismaLink {
  post(
    description: "Prisma turns your database into a GraphQL API 😎",
    url: "https://www.prismagraphql.com"
  ) {
    id
  }
}

mutation CreateApolloLink {
  post(
    description: "The best GraphQL client for React",
    url: "https://www.apollographql.com/docs/react/"
  ) {
    id
  }
}

에디터에 2개의 뮤테이션을 동시에 추가했으므로, 각 뮤테이션들은 동작 이름이 있어야 합니다. 지금은 각각을 CreatePrismaLinkCreateApolloLink로 지었습니다.

두 패널 가운데의 재생 버튼을 클릭하고, 드롭다운 메뉴에서 한번에 하나씩 선택하여 실행해봅니다.

이렇게 하면 데이터베이스에 새로운 Link 레코드가 2개 생성됩니다. 뮤테이션이 실제로 작동하였다는 것을 확인하려면, 아래의 쿼리를 Playground에서 보내면 됩니다.

{
  feed {
    links {
      id
      description
      url
    }
  }
}

참고: app 섹션의 default Playground에서 feed 쿼리를 전송할 수도 있습니다.

모든 것이 제대로 작동하였다면, 쿼리는 아래와 같은 데이터를 반환할 것입니다. 아래 결과에서 id는 Prisma 전체에 걸쳐 유일한 값이므로, 당연히 여러분의 경우와 다른 값이 나올 것입니다.

{
  "data": {
    "feed": {
      "links": [
        {
          "id": "cjcnfwjeif1rx012483nh6utk",
          "description": "The best GraphQL client",
          "url": "https://www.apollographql.com/docs/react/"
        },
        {
          "id": "cjcnfznzff1w601247iili50x",
          "description": "Prisma turns your database into a GraphQL API 😎",
          "url": "https://www.prismagraphql.com"
        }
      ]
    }
  }
}

아주 좋아요, 서버가 제대로 작동하는군요! 👏

Quiz

백엔드 설계에서 Prisma를 사용할 때, 2개의 GraphQL API 계층이 존재하는 이유로 적절한 것은?

  • GraphQL 서버의 견고함과 안정성을 향상시키기 위함이다 (한 계층이 무력화되어도, 두번째 계층에 의하여 유지)
  • GraphQL의 성능을 향상시키기 위함이다 (여러 계층을 통과하면서 요청이 가속화된다)
  • Prisma가 CRUD 동작을 제공하는 데이터베이스 계층을 제공한다. 두번째 계층은 비즈니스 로직과 공통 작업 흐름(인증 등)을 위한 어플리케이션 계층이다.
  • 두 개의 GraphQL 계층을 갖는 것은 GraphQL 명세에 따르면 지키기 힘든 요구 조건이다.

0개의 댓글