GraphQL - GraphQL Server ์‹œ์ž‘ํ•˜๊ธฐ

2026. 1. 2. 16:43ยท๐Ÿงฌ GraphQL

GraphQL

 

 

โœ… 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


https://altairgraphql.dev/

 

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
'๐Ÿงฌ GraphQL' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • GraphQL - GraphQL Client ์‹œ์ž‘ํ•˜๊ธฐ
j2yonghwa
j2yonghwa
Trying to be a fullstack developer ๐Ÿš€
  • j2yonghwa
    j2yonghwa
    j2yonghwa
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (156)
      • โฐ Daily WakaTime (1)
      • ๐Ÿ–๏ธ ๋…ธ๋งˆ๋“œ์ฝ”๋” (2)
      • ๐Ÿบ Dev Setup (3)
      • ๐Ÿ”ญ Tech Info (1)
      • ๐Ÿšซ Error (1)
      • ๐Ÿ“‚ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (23)
      • ♣๏ธ Next.js 14 (10)
      • ♠๏ธ Next.js 12 (20)
      • ๐Ÿ›ธ React Native (12)
      • ๐Ÿฆ‹ TypeScript (1)
      • ๐Ÿ Python (2)
      • ๐ŸŒŠ TailwindCSS (4)
      • ๐Ÿงฉ SQL (25)
      • ๐Ÿ’Ž Prisma (5)
      • ๐ŸŒฑ MongoDB (4)
      • ๐ŸŽฏ Redis (1)
      • ๐Ÿงฌ GraphQL (2)
      • ๐Ÿ”ฅ Firebase (7)
      • ๐Ÿ’ธ Third-Party Services (2)
      • ๐Ÿ•ธ๏ธ Web (1)
      • ๐Ÿ† ์ฝ”๋”ฉํ…Œ์ŠคํŠธ (23)
      • ๐Ÿ“™ ๋ชจ๋”ฅ๋‹ค (5)
      • ๐Ÿ“— ์ฝ”ํ…Œ ํ•ฉ๊ฒฉ์ž ๋˜๊ธฐ -JS- (0)
      • ๐Ÿ“˜ ํด๋ฆฐ์ฝ”๋“œ (0)
      • ๐Ÿฏ ๊ฟ€ํŒ ๐Ÿ (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

    • ๊นƒํ—™
  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    MySQL
    SQL
    Python
    API
    React Native
    next.js 14
    dev setup
    mongoDB
    0๋ ˆ๋ฒจ
    ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    next.js 12
    Next.js
    PostgreSQL
    ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ
    ์ฝ”๋”ฉํ…Œ์ŠคํŠธ ์ž…๋ฌธ
    Firebase
    Prisma
    react router
    tailwindcss
    ๋ชจ๋”ฅ๋‹ค
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
j2yonghwa
GraphQL - GraphQL Server ์‹œ์ž‘ํ•˜๊ธฐ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”