
โ GraphQL?
GraphQL
API๋ฅผ ์ํ ์ฟผ๋ฆฌ ์ธ์ด
GraphQL์ ํด๋ผ์ด์ธํธ๊ฐ ํ์ํ ๊ฒ์ ์ ํํ๊ฒ ์์ฒญํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉฐ, ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ API๋ฅผ ๋ ์ฝ๊ฒ ๋ฐ์ ์ํค๊ณ ๊ฐ๋ ฅํ ๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ํ์ฑํํฉ๋๋ค.
https://graphql.org/
Graphile
PostgreSQL๋ฅผ ์ํ ํ์ฅ ๊ฐ๋ฅํ ๊ณ ์ฑ๋ฅ ์๋ GraphQL API
https://www.graphile.org/
Hasura
๋ชจ๋ ๋ฐ์ดํฐ์ ๋ํ ์ฆ๊ฐ์ ์ธ GraphQL
Hasura๋ ์ ๊ท ๋ฐ ๊ธฐ์กด ๋ฐ์ดํฐ ์์ค์ ๋ํ ์ฆ๊ฐ์ ์ธ GraphQL ๋ฐ REST API๋ฅผ ์ ๊ณตํฉ๋๋ค. Hasura๋ฅผ ๋ฐ์ดํฐ์ ์ฐ๊ฒฐํ๊ณ 1๋ถ ์ด๋ด์ API๋ฅผ ๋ฐ์ผ์ธ์.
https://hasura.io/
โ API๋?
API (Application Programming Interface)
API๋ ์ปดํจํฐ๋ ์ปดํจํฐ ํ๋ก๊ทธ๋จ ์ฌ์ด์ ์ฐ๊ฒฐ์ด๋ค. ์ฆ, ํ๋ก๊ทธ๋จ๋ค์ด ์๋ก ์ํตํ๋ ๋ฐฉ๋ฒ์ด๋ค.
์ฃผ๋ก ํ๋ก๊ทธ๋๋ฐํ ๋ ์ฌ์ฉํ๊ณ , ์ดํ๋ฆฌ์ผ์ด์
๊ณผ ์ํธ์์ฉํ ๋ ์ฌ์ฉํ๋ค.
์ธํฐํ์ด์ค
๋ฌด์์ธ๊ฐ์(TV) ๋ฌด์ธ๊ฐ๋ฅผ(๋ฆฌ๋ชจ์ปจ) ์ด์ฉํด์ ์ํธ์์ฉํ๋ ๋ฐฉ์์ด๋ค.
๋ฆฌ๋ชจ์ปจ์ ์ด์ฉํด์ TV๋ฅผ ์ปจํธ๋กคํ๊ณ , TV์ ์ํธ์์ฉํ ์ ์๋ ๊ฒ์ด๋ค.
Web API
https://developer.mozilla.org/ko/docs/Web/API
โ REST API๋?
“REST๋ผ๋ ์ค๊ณ ์์น์ ๋ฐ๋ฅด๋๋ก ๋ง๋ HTTP ๊ธฐ๋ฐ API”
- REST = ์ค๊ณ ์ฒ ํ
- API = ๊ทธ ์ฒ ํ์ ๊ตฌํํ ์ธํฐํ์ด์ค

GraphQL์ด ํด๊ฒฐํ๋ REST API์ ๋ฌธ์ ์
1. Overfetching
ํ์ํ ๋ฐ์ดํฐ๋ณด๋ค ๋ ๋ง์ ๋ฐ์ดํฐ๋ฅผ fetchํ๋ ๊ฒ์ ๋งํฉ๋๋ค.
GraphQL์ ์ฌ์ฉํ๋ฉด API์ GraphQL ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋ด๊ณ ํ์ํ ๊ฒ๋ง ์ ํํ ์ป์ ์ ์์ต๋๋ค.
GraphQL ์ฟผ๋ฆฌ๋ ํญ์ ์์ธก ๊ฐ๋ฅํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.
2. Underfetching
ํ์ํ ๋ฐ์ดํฐ๋ณด๋ค ์ ์ ๋ฐ์ดํฐ๋ฅผ fetchํ๋ ๊ฒ์ ๋งํฉ๋๋ค.
์ผ๋ฐ์ ์ธ REST API๋ ์ฌ๋ฌ URL์์ ๋ก๋ฉํด์ผ ํ์ง๋ง GraphQL API๋ ์ฑ์ ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋จ์ผ request๋ก ๊ฐ์ ธ์ต๋๋ค. GraphQL์ ์ฌ์ฉํ๋ ์ฑ์ ๋๋ฆฐ ๋ชจ๋ฐ์ผ ๋คํธ์ํฌ ์ฐ๊ฒฐ์์๋ ๋น ๋ฅผ ์ ์์ต๋๋ค.
โ Apollo Server
Apollo Server์๊ฐ
Apollo ์๋ฒ๋ Apollo ํด๋ผ์ด์ธํธ๋ฅผ ํฌํจํ ๋ชจ๋ GraphQL ํด๋ผ์ด์ธํธ์ ํธํ๋๋ ์ฌ์ ์ค์(spec-compliant)์ ์คํ ์์ค GraphQL ์๋ฒ์
๋๋ค. ๋ชจ๋ ์์ค์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ ์์ฒด ๋ฌธ์ํ ๊ฐ๋ฅํ production-ready GraphQL API๋ฅผ ๊ตฌ์ถํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์
๋๋ค.
https://www.apollographql.com/docs/apollo-server/
Apollo Server์์ํ๊ธฐ
npm install apollo-server graphql
npm install nodemon -D
```
const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
});
server.listen().then(({ url }) => {
console.log(`๐ Server ready at ${url}`);
});
โ GraphQL Schema ์ ์ (type, query, mutation)
GraphQL์ Schema๊ฐ ํ์ํ๋ค.
๊ทธ ์ค์์๋ Query type์ ํ์
Query์ Mutation
import { ApolloServer, gql } from "apollo-server";
const typeDefs = gql`
type User {
id: ID!
username: String!
firstName: String!
lastName: String
}
type Tweet {
id: ID!
text: String!
author: User!
}
type Query {
allTweets: [Tweet!]!
tweet(id: ID!): Tweet
}
type Mutation {
postTweet(text: String!, userId: ID!): Tweet!
deleteTweet(id: ID!): Boolean!
}
`;
const server = new ApolloServer({ typeDefs });
server.listen().then(({ url }) => {
console.log(`Running on ${url}`);
});
โ Resolvers
const server = new ApolloServer({ typeDefs, resolvers });
์ด์ ๊ฐ์ด ApolloServer๋ typeDefs์ resolvers๋ฅผ ๋ฐ๋๋ค.
typeDefs๋ ์์์ ์์ฑํ type๋ค๊ณผ query, mutation์ด ๋ค์ด๊ฐ๊ณ ,
resolvers๋ ์์ฑํ type๊ณผ query, mutation์ ๋ฐํ์ผ๋ก ์ค์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ํจ์๋ค์ด ๋ค์ด๊ฐ๋ค.
resolvers๋ object๋ค.
const resolvers = {
Query: {
allTweets() {
return tweets;
},
tweet(root, { id }) {
return tweets.find((tweet) => tweet.id === id);
},
},
};
resolver function์ ์ฒซ ๋ฒ์งธ arg์๋ root๋ผ๋ ๊ฐ์ด ๋ค์ด์ค๊ณ , ๋ ๋ฒ์งธ arg์๋ query๋ mutation์ ์ฌ์ฉํ arg๊ฐ ๋ค์ด์จ๋ค.
โ Type Resolvers
let users = [
{
id: "1",
firstName: "nico",
lastName: "las",
},
{
id: "2",
firstName: "elon",
lastName: "musk",
},
];
๋ง์ฝ ์์ ๊ฐ์ user ๋ฐ์ดํฐ๊ฐ ์๋ค๊ณ ํ์ ๋, user์ type์ fullName์ด ์๋ค๋ฉด, query๋ก ๋ชจ๋ user์ ์ ๋ณด๋ค์ ๋ถ๋ฌ์ฌ ๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
const typeDefs = gql`
type User {
id: ID!
firstName: String!
lastName: String!
fullName: String!
}
๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ ์๋ fullName์ ๋์ ์ผ๋ก query ํด์์ผ ํ๋ค.
์ด๋ ํ type์๋ resolver field๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
import { ApolloServer, gql } from "apollo-server";
let tweets = [
{
id: "1",
text: "first one!",
userId: "2",
},
{
id: "2",
text: "second one!",
userId: "1",
},
];
let users = [
{
id: "1",
firstName: "nico",
lastName: "las",
},
{
id: "2",
firstName: "elon",
lastName: "musk",
},
];
const typeDefs = gql`
type User {
id: ID!
firstName: String!
lastName: String!
fullName: String!
}
type Tweet {
id: ID!
text: String!
author: User
}
type Query {
allUsers: [User!]!
allTweets: [Tweet!]!
tweet(id: ID!): Tweet
}
type Mutation {
postTweet(text: String!, userId: ID!): Tweet!
deleteTweet(id: ID!): Boolean!
}
`;
const resolvers = {
Query: {
allTweets() {
return tweets;
},
tweet(root, { id }) {
return tweets.find((tweet) => tweet.id === id);
},
allUsers() {
console.log("allUsers called!");
return users;
},
},
Mutation: {
postTweet(_, { text, userId }) {
const newTweet = {
id: tweets.length + 1,
text,
userId,
};
tweets.push(newTweet);
return newTweet;
},
deleteTweet(_, { id }) {
const tweet = tweets.find((tweet) => tweet.id === id);
if (!tweet) return false;
tweets = tweets.filter((tweet) => tweet.id !== id);
return true;
},
},
User: {
fullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
},
},
Tweet: {
author({ userId }) {
const user = users.find((user) => user.id === userId);
return user;
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Running on ${url}`);
});
Query ํ์ ๊ณผ Mutation ํ์ ์ resolver field๋ฅผ ์ค ๊ฒ์ฒ๋ผ User ํ์ ์๋ resolver field๋ฅผ ์ค ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์์์ ์ธ๊ธํ์๋ resolver function์ ์ฒซ ๋ฒ์งธ arg์ธ root์๋ ํด๋น ํ๋๋ฅผ ์์ ํ ์์ ํ์ ์ resolver๊ฐ ๋ฐํํ ๊ฐ์ฒด๊ฐ ๋ด๊ฒจ์๋ค.
Resolver ํจ์์๋ parent(root or source), args, context, info ์ ๋ค ๊ฐ์ง ์ธ์๊ฐ ์์๋๋ก ์ ๋ฌ๋ฉ๋๋ค.
User: {
fullName: (parent, args, context, info) => {
return "hello";
},
},
โ Document ์์ฑ ๋ฐฉ๋ฒ
type Mutation {
postTweet(text: String!, userId: ID!): Tweet!
"""
Deletes a Tweet if found, else returns false
"""
deleteTweet(id: ID!): Boolean!
}
"""์ฌ์ด์ ์ค๋ช ์ ์ ์ด์ค๋ค.
โ Tools: Apollo Studio & Altair GraphQL Client
Altair GraphQL Client
Altair is a feature-rich GraphQL Client IDE for all platforms. Enables you interact with any GraphQL server you are authorized to access from any platform you are on.
altairgraphql.dev
์น ๋ฒ์ ์ผ๋ก๋ ์ฌ์ฉ ๊ฐ๋ฅํ๋ฉฐ, ์ค์นํ์ฌ offline์ผ๋ก๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
โ Migrating from REST to GraphQL
async allMovies() {
const response = await (
await fetch("https://yts.torrentbay.st/api/v2/list_movies.json")
).json();
return response.data.movies;
},
async movie(_, { id }) {
const response = await (
await fetch(
`https://yts.torrentbay.st/api/v2/movie_details.json?movie_id=${id}`
)
).json();
return response.data.movie;
},
fetch๋ฅผ ์ฌ์ฉํ์ฌ REST API์ ๋ฐํ๊ฐ์ GraphQL๋ก ๊ฐ์ธ ๋ฐํํด์ค๋ค.
'๐งฌ GraphQL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| GraphQL - GraphQL Client ์์ํ๊ธฐ (0) | 2026.01.07 |
|---|