Graph QL(2) - Apollo
๐์์ํ๋ฉฐ
Graph QL ๊ด๋ จ ์๋ฃ๋ฅผ ์ฐพ๋ค๋ณด๋, Apollo๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒ์ ๋ณด์๋ค.๐ Apollo๋ ๋ฌด์์ธ์ง, ์ด๋ป๊ฒ ์ ์ฉํ ์ ์๋์ง ์์๋ณด๊ณ Graph QL ๊ด๋ จ๋ ์ ํ๋ธ ์์์์ ๋ฐฐ์ด ๋ด์ฉ์ ๋๋ฆ๋๋ก ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค.
โ Apollo๋?
๊ณต์ ๋ฌธ์์ ์ค๋ช ์ ์ดํด๋ณด์.
Apollo๋ ๋ฐ์ดํฐ๋ฅผ ํตํฉํ๊ณ ์๋น์ค๋ค์ ๋จ์ผ ๋ถ์ฐ GraphQL API์ธ ์ํผ๊ทธ๋ํ(supergraph)๋ก ํตํฉํ ์ ์๋ ๊ฐ๋ฐ์ ํ๋ซํผ๊ณผ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ค. Apollo๋ ์ฒ์์ผ๋ก API๋ฅผ ๊ตฌ์ถํ๊ฑฐ๋ API๋ฅผ ์ฟผ๋ฆฌํ๊ฑฐ๋, ํ๋ซํผ์ ์ํผ๊ทธ๋ํ๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ ๋๊น์ง, ์ด๋ค ๋จ๊ณ๋ ๊ท๋ชจ์์๋ GraphQL์ด ํจ๊ณผ์ ์ผ๋ก ์๋ํ๋๋ก ๋์์ค๋ค.
์ํผ๊ทธ๋ํ : ์ฌ๋ฌ ๊ฐ์ GraphQL ์๋น์ค์ ๋ฐ์ดํฐ ์์ค๋ฅผ ํ๋์ ํต์ผ๋ GraphQL API๋ก ํฉ์น ๊ฒ
์ฆ, Apollo๋ ๋ฐ์ดํฐ์ ์๋น์ค๋ฅผ ๊ฐ๋จํ๊ฒ ํตํฉํ๊ณ ๊ด๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๊ณ , GraphQL์ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ก ๋์์ฃผ๋ ๋๊ตฌ๋ค.
โ Apollo Server
Apollo Server๋ ์ฌ์์ ์ค์ํ๋ ์คํ ์์ค GraphQL ์๋ฒ๋ก, Apollo ํด๋ผ์ด์ธํธ๋ฅผ ๋น๋กฏํ ๋ชจ๋ GraphQL ํด๋ผ์ด์ธํธ์ ํธํ๋๋ค.
Apollo Server๋ฅผ ํตํด ๊ฐ๋จํ ์ค์ ์ผ๋ก ๊ฐ๋ฐ์๊ฐ ๋น ๋ฅด๊ฒ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค!
โก๏ธํ๋ก์ ํธ ์์
๐ 1. ์ ํ๋ก์ ํธ ๋ง๋ค๊ธฐ
1
2
mkdir graphql-server-example
cd graphql-server-example
๐ 2. package.json ์์ฑ
1
npm init --yes && npm pkg set type="module"
๐ 3. ์ข
์์ฑ ์ค์น
1
npm install @apollo/server graphql
โก๏ธ GraphQL schema ์ค์
์ฐธ๊ณ ๋ก, typeDefs = `` ๋ก ์์ฑํ๋ฉด ์์ schema ๋ค์ด string ์ฒ๋ผ ํ์๋๋๋ฐ, vsCode ํ์ฅํ๋ก๊ทธ๋จ์ ์ค์นํ๋ฉด ์ ์ ํ๊ฒ ์ปฌ๋ฌ๊ฐ ๋ณ๊ฒฝ๋์ด ๋ณด๊ธฐ ์ข์์ง๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
import { ApolloServer } from "@apollo/server"
import { startStandaloneServer } from "@apollo/server/standalone"
const typeDefs = `
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`
ํ๋์ฉ ์ดํด๋ณด์.
์์ | ์ค๋ช |
---|---|
typeDefs | GraphQL ์คํค๋ง ์ธ์ด๋ก ์์ฑ๋ ๋ฌธ์์ด |
type Book | Book ํ์ ์ ๋ํ ๋ฐ์ดํฐ ๋ชจ๋ธ ์ ์ |
type Query | ํด๋ผ์ด์ธํธ๊ฐ ์คํํ ์ ์๋ ์ฟผ๋ฆฌ๋ฅผ ์ ์ API์ ์ง์ ์ ์ญํ ๋ก, ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ ์ ์๋์ง ๊ท์ |
๋ค์๊ณผ ๊ฐ์ด ๋ฐ์ดํฐ ๋ชจ๋ธ์ ์ถ๊ฐํ ์ ์๋ค!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const typeDefs = `
type Book {
title: String
author: String
}
type Movie {
title: String
release: Int
}
type Query {
books: [Book]
movies: [Movie]
}
`
โก๏ธdata set ์ค์
์์์๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ์ํ์ผ๋, ๋ฐ์ดํฐ๋ฅผ ์ ์ํ์. ์์์ type Query {books: [Book]}
๋ฅผ ์์ฑํ๋๋ฐ ์ฌ๊ธฐ์ books๋ฅผ ์ง์ ํด์ค๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.
1
2
3
4
5
6
7
8
9
10
const books = [
{
title: "The Awakening",
author: "Kate Chopin",
},
{
title: "City of Glass",
author: "Paul Auster",
},
]
โก๏ธresolver ์ ์
data set์ ์ ์ํ์ง๋ง, Apollo Sever๋ ์ฟผ๋ฆฌ๋ฅผ ์คํํ ๋ ํด๋น data set์ ์ฌ์ฉํด์ผ ํ๋ค๋ ๊ฒ์ ์์ง ๋ชปํ๊ธฐ ๋๋ฌธ์, resolver๋ฅผ ์์ฑํ๋ค.
1
2
3
4
5
const resolvers = {
Query: {
books: () => books,
},
}
โก๏ธApolloSever ์ธ์คํด์ค ์์ฑ
1
2
3
4
5
6
7
8
9
10
11
//์คํค๋ง ์ ์์ ๋ฆฌ์กธ๋ฒ ์งํฉ ๋ ๊ฐ์ ๋งค๊ฐ๋ณ์๋ฅผ ์์ฑํ๋ค.
const server = new ApolloServer({
typeDefs,
resolvers,
})
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
})
console.log(`๐ Server ready at: ${url}`)
โ Apollo Client
Apollo Client๋ JavaScript๋ฅผ ์ํ ์ข ํฉ์ ์ธ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด GraphQL๋ก ๋ก์ปฌ ๋ฐ ์๊ฒฉ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ๊ด๋ฆฌํ ์ ์๋ค. ์ด๋ฅผ ์ด์ฉํด ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ , ์บ์ํ๊ณ , ์์ ํ๋ ๋์์ UI๋ฅผ ์๋์ผ๋ก ์ ๋ฐ์ดํธํ ์ ์๋ค.
ํต์ฌ @apollo/client
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ React์์ ํตํฉ์ ์ ๊ณตํ๋ค.
โก๏ธํ๋ก์ ํธ ์์
๐ 1. vite ์ด์ฉํด React ์ธํ
1
npm create vite@latest
๐ 2. ๋ชจ๋ ์ค์น
๋ ๊ฐ์ง ์ต์์ ์ข
์์ฑ์ ์ค์นํ๋ค.
@apollo/client
: Apollo ํด๋ผ์ด์ธํธ๋ฅผ ์ค์ ํ๋ ๋ฐ ์ฌ์ฉํ๋ค. ์ธ๋ฉ๋ชจ๋ฆฌ ์บ์, ๋ก์ปฌ ์ํ ๊ด๋ฆฌ, ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ React ๊ธฐ๋ฐ ๋ทฐ ๋ ์ด์ด๊ฐ ํฌํจ๋๋ค.graphql
: ์ด ํจํค์ง๋ GraphQL ์ฟผ๋ฆฌ ๊ตฌ๋ฌธ ๋ถ์์ ์ํ ๋ก์ง์ ์ ๊ณตํ๋ค.
1
npm install @apollo/client graphql
โก๏ธApolloClient ์ด๊ธฐํ
1
2
3
4
5
6
7
8
9
10
11
12
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
gql,
} from "@apollo/client"
//ํ์ฌ ๋ก์ปฌ ํ๊ฒฝ์์ ์คํ ๋๋ฏ๋ก uri๋ ์์์ ์ค์ ํ 4000๋ฒ
const client = new ApolloClient({
uri: "http://localhost:4000/",
cache: new InMemoryCache(),
})
uri
: GraphQL ์๋ฒ์ URL์ ์ง์ .cache
: ์ํด๋ก ํด๋ผ์ด์ธํธ๊ฐ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์จ ํ ์บ์ฑํ๋ ๋ฐ ์ฌ์ฉํ๋ InMemoryCache์ ์ธ์คํด์ค.
โก๏ธ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
๋์ผํ ํ์ผ ์์์, ์ฟผ๋ฆฌ ๋ฌธ์์ด(gql ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด๋ก ๋ํ)์ ์ฌ์ฉํ์ฌ client.query()๋ฅผ ํธ์ถํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
client
.query({
query: gql`
query GetBooks {
books {
title
author
}
}
`,
})
.then((result) => console.log(result.data.books))
.catch((error) => console.error(error))
โก๏ธ๋ฆฌ์กํธ์์ ํจ๊ป ์ฌ์ฉํ๊ธฐ
์์ ๊ฐ์ด ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์์ ์ฌ์ฉํ ์๋ ์์ง๋ง, ๋ฆฌ์กํธ์์ ๋ ํธ๋ฆฌํ๊ฒ ์ด์ฉํ ์ ์๋ ๋ฐฉ๋ฒ๋ ์๋ค.
๐ 1. ApolloProvider ๊ฐ์ธ๊ธฐ
React์ Context.Provider ์ฒ๋ผ ApolloProvider๋ฅผ ์ด์ฉํด React ์ฑ์ ๋ํํ๊ณ Apollo ํด๋ผ์ด์ธํธ๋ฅผ ์ปจํ
์คํธ์ ๋ฐฐ์นํ์.
1
2
3
4
5
6
7
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>
)
๐ 2. ApolloProvider ๊ฐ์ธ๊ธฐ
ApolloProvider๊ฐ ์ฐ๊ฒฐ๋๋ฉด, useQuery๋ก ๋ฐ์ดํฐ ์์ฒญ์ ์์ํ ์ ์๋ค. useQuery ํ
์ GraphQL ๋ฐ์ดํฐ๋ฅผ UI์ ๊ณต์ ํ๋ React ํ
์ด๋ค!
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
32
33
34
35
36
37
import { useQuery, gql } from "@apollo/client"
// books ์ฟผ๋ฆฌ ์ ์
const GET_BOOKS = gql`
query GetBooks {
books {
title
author
}
}
`
// DisplayBooks ์ปดํฌ๋ํธ
function DisplayBooks() {
const { loading, error, data } = useQuery(GET_BOOKS)
if (loading) return <p>Loading...</p>
if (error) return <p>Error : {error.message}</p>
return data.books.map(({ title, author }, index) => (
<div key={index}>
<h3>{title}</h3>
<p>{author}</p>
<br />
</div>
))
}
// App ์ปดํฌ๋ํธ ์
๋ฐ์ดํธ
export default function App() {
return (
<div>
<h2>My first Apollo app ๐</h2>
<DisplayBooks />
</div>
)
}