- 본 시리즈에서는 How to GraphQL의 Tutorial 문서들을 차례대로 번역합니다.
- 이 글은 GraphQL React + Apollo Tutorial - Getting Started을 번역한 글입니다.
- 본 시리즈는 GraphQL Basic and Advanced 시리즈와 GraphQL-Node Tutorial 시리즈에서 이어집니다. GraphQL을 처음 접하는 분들은 해당 시리즈를 먼저 읽고 오시는 것을 추천드립니다.
- 오역 또는 의역이 있을 수 있습니다. 양해 부탁드리며, 수정이 필요한 부분은 댓글로 요청해주세요.
이 튜토리얼은 프론트엔드를 다루므로, 백엔드를 구현하는 과정은 생략하는 대신 Node.js 튜토리얼에서 만든 서버를 사용하도록 하겠습니다.
React 어플리케이션을 모두 만들고 나면, 백엔드와 연동하기 위하여 필요한 코드를 삽입할 수 있게 됩니다.
참고: 이 튜토리얼로 완성한 프로젝트는 GitHub에서 확인할 수 있습니다. 본 튜토리얼 코스의 이어지는 장에서 만약 내용을 잘 따라오지 못하신다면, 얼마든지 링크를 참조하시며 활용하시기 바랍니다. 도한 각 코드 블록에는 대응하는 파일명이 함께 적혀있습니다. 해당 표기를 클릭하면 GitHub 상의 대응하는 파일로 바로 링크됩니다. 이를 참조하면 코드를 어디에 입력할지, 최종 결과물은 어떤 모습인지 등을 확실히 알 수 있습니다.
제일 먼저, 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.css
와index.css
는 스타일을 포함하므로,styles
로 이동시킵니다. 또한 각.css
파일을 참조하는index.js
와App.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의 React 바인딩을 설치해야 합니다. 몇 가지 패키지들로 이루어져 있습니다.
($ .../hackernews-react-apollo)yarn add apollo-boost react-apollo graphql
설치한 패키지들에 대하여 간단히 알아보겠습니다.
apollo-boost
는 Apollo 클라이언트를 다루는 데에 필요한 몇가지 패키지들을 한번에 설치해주는 편리한 모음 패키지입니다. 아래 패키지들을 포함합니다.apollo-client
: 모든 마술이 이루어지는 곳!apollo-cache-inmemory
: 추천하는 캐시 라이브러리apollo-link-http
: 원격 데이터 불러오기에 필요한 Apollo Linkapollo-link-error
: 오류 처리를 위한 Apollo Linkapollo-link-state
: 로컬 상태 관리를 위한 Apollo Linkgraphql-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값을 표기할 때 큰 따옴표("")를 사용합니다. 여러분이 튜토리얼을 보며 추가하는 코드는 모두 세미콜론을 사용하지 않고, 대부분 작은 따옴표를 사용합니다. 기존에 이미 있었던 세미콜론을 지우거나, 큰따옴표를 작은 따옴표로 바꿔도 됩니다. 🔥
코드 주석에 적힌 번호들을 바탕으로 각각을 살펴보도록 하겠습니다.
설치한 패키지로부터 필수 의존성들을 불러옵니다.
httpLink
를 생성합니다. httpLink
는 GraphQL API를 사용하여 ApolloClient
인스턴스에 연결합니다. GraphQL 서버는 http://localhost:4000
에서 동작하고 있어야 합니다.
이제 httpLink
를 인자로 전달하여 ApolloClient
인스턴스를 생성하고, InMemoryCache
인스턴스를 새로 생성합니다.
마지막으로 React 어플리케이션의 최상위 컴포넌트를 렌더링합니다. App
은 고차 컴포넌트 ApolloProvider
로 감싸지고, client
를 props로 전달받습니다.
앞서 언급한 대로, 이번 튜토리얼의 백엔드는 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
}
이 스키마는 아래와 같은 동작을 허용합니다.
feed
: 백엔드로부터 모든 링크들을 반환합니다. 참고로 이 쿼리는 필터링, 정렬, 페이지 매기기 기능을 위한 인자를 받을 수 있습니다.post
: 인증된 사용자가 새로운 링크를 생성합니다.signup
: 새로운 사용자를 위한 계정을 생성합니다.login
: 기존의 사용자가 로그인합니다.vote
: 인증된 사용자가 어떤 링크에 대하여 투표합니다.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
}
}
}
서버를 시동하고 쿼리와 뮤테이션을 보내기에 앞서, 마지막으로 할 일이 하나 남았습니다. 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 start
는 package.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개의 뮤테이션을 동시에 추가했으므로, 각 뮤테이션들은 동작 이름이 있어야 합니다. 지금은 각각을 CreatePrismaLink
와 CreateApolloLink
로 지었습니다.
두 패널 가운데의 재생 버튼을 클릭하고, 드롭다운 메뉴에서 한번에 하나씩 선택하여 실행해봅니다.
이렇게 하면 데이터베이스에 새로운 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 명세에 따르면 지키기 힘든 요구 조건이다.