티스토리 뷰

자바스크립트

[23년 업데이트] graphQL에 관하여 // graphQL 이용해보기

YG - 96년생 , 강아지 있음, 개발자 희망 2022. 3. 27. 08:22

graphQL이란?

그래프 QL은 페이스북이 2012년에 개발하여 2015년에 공개적으로 발표된 데이터 질의어이다. 그래프 QL은 REST 및 부속 웹서비스 아키텍처를 대체할 수 있다. 클라이언트는 필요한 데이터의 구조를 지정할 수 있으며, 서버는 정확히 동일한 구조로 데이터를 반환한다.

 

장점

1. Overfetching을 없앨 수 있다.

예를 들어 모든 사용자 이름을 GET으로 가져오는데 사용자 이름과 더불어 프로필 사진, 전화번호, 이메일 등 필요한 정보보다 더 많이 서버로부터 받는  것을 Overfetching이라고 하는데 graphQL을 사용한다면 필요한 정보만 가져올 수 있어서 Overfetching을 막을 수 있다.

 

2. UnderFetching을 막을 수 있다.

UnderFetching이란 화면을 구성하는데 유저의 API , 알림 API , 글 목록 API 등 3가지의 API를 받아서 화면을 구성해야만 화면을 띄울 수 있다면 이런 것이 underFetching이라고 한다. graphQL을 사용한다면 한 쿼리에 정확한 정보만 담아서 이용할 수 있게 된다. 

 

23년도 아폴로 서버 사용 방법

 

npm i apollo-server graphql

 

Apollo 서버는 Apollo 클라이언트를 포함한 모든 GraphQL 클라이언트와 호환되는 오픈 소스 사양 호환 GraphQL 서버입니다. 모든 소스의 데이터를 사용할 수 있는 프로덕션 준비가 된 자체 문서화 GraphQL API를 구축하는 가장 좋은 방법입니다.

 

 

 

@apollo/server

Core engine for Apollo GraphQL server. Latest version: 4.6.0, last published: 7 days ago. Start using @apollo/server in your project by running `npm i @apollo/server`. There are 110 other projects in the npm registry using @apollo/server.

www.npmjs.com

 

 

graphql

A Query Language and Runtime which can target any service.. Latest version: 16.6.0, last published: 8 months ago. Start using graphql in your project by running `npm i graphql`. There are 12540 other projects in the npm registry using graphql.

www.npmjs.com

 

 

Schema

 

typeDefs에 무조건 Query라는 타입이 있어야 합니다. rest API로 치자면 /allTweets , /tweet/:id와 같이 URL에서 찾아주는 역할을 하는 타입이라고 합니다. 또한 아폴로 서버에서 제공하는 사이트를 이용해서 API를 테스트해 볼 수 있습니다.

 

server.js

import { ApolloServer, gql } from 'apollo-server';

const typeDefs = gql`
  type User {
    id: ID
    username: String
  }

  type Tweet {
    id: ID
    text: String
    author: User
  }

  type Query {
    allTweets: [Tweet]
    tweet(id: ID): Tweet
  }
`;

const server = new ApolloServer({ typeDefs });

server.listen().then(({ url }) => {
  console.log(`Running on ${url}`);
});

 

 

 

 

Mutation

graphQL에서는 Query 혹은 Mutation 둘 중 하나만 사용합니다.

 

Query는 RestAPI에서 GET의 역할을 합니다.

Mutation은 RestAPI에서 PUT, POST, DELETE의 역할을 합니다.

 

const typeDefs = gql`
  type User {
    id: ID
    username: String
  }

  type Tweet {
    id: ID
    text: String
    author: User
  }

  type Query {
    allTweets: [Tweet]
    tweet(id: ID): Tweet
  }

  type Mutation {
    postTweet(userId: ID, text: String): Tweet
    deleteTweet(id: ID): Tweet
  }
`;

 

 

 

Queries and Mutations | GraphQL

Queries and Mutations On this page, you'll learn in detail about how to query a GraphQL server. Fields# At its simplest, GraphQL is about asking for specific fields on objects. Let's start by looking at a very simple query and the result we get when we run

graphql.org

 

! 의 유무

! 는 Null일수도 있는지 아닌지 체크해 주는 역할입니다.! 를 붙이면 불러오고자 하는 대상이 Null일 때 에러로 개발자에게 알려줍니다.

  type Tweet {
    id: ID! // id는 Null 값이 아니다
    text: String // text는 String 값이거나 Null 값이다.
    author: User // author는 User 이거나 Null 값이다.
  }

 

Resolvers

resolver 함수는 데이터베이스에 액세스 한 다음 데이터를 반환합니다.

 

import { ApolloServer, gql } from 'apollo-server';

const tweets = [
  {
    id: '1',
    text: 'first one!',
  },
  {
    id: '2',
    text: 'second one',
  },
];

const typeDefs = gql`
  type User {
    id: ID
    username: String
  }

  type Tweet {
    id: ID!
    text: String
    author: User
  }

  type Query {
    allTweets: [Tweet]
    tweet(id: ID): Tweet
  }

  type Mutation {
    postTweet(userId: ID, text: String): Tweet
    deleteTweet(id: ID): Tweet
  }
`;

const resolvers = {
  Query: {
    allTweets() {
      return tweets;
    },
    tweet(root, { id }) {
      return tweets.find(tweet => tweet.id === id);
    },
  },
};

const server = new ApolloServer({ typeDefs, resolvers });

server.listen().then(({ url }) => {
  console.log(`Running on ${url}`);
});

 

 

Execution | GraphQL

Execution After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON. GraphQL cannot execute a query without a type system, let's use an example type system

graphql.org

 

Resolvers Args

첫 번째 인자인 root는 자신을 포함하고 있는 부모를 뜻합니다. 두 번째 인자는 Mutation에서 인자로 id, text 등을 주었을 때 두 번째 인자에서 확인할 수 있습니다.

const users = [
  {
    id: '1',
    firstName: 'Kim',
    lastName: 'YoungGil',
  },
];



const typeDefs = gql`
  type User {
    id: ID
    firstName: String
    lastName: String
    fullName: String
  }

  type Query {
    allUsers: [User]
  }
`;

const resolvers = {
  Query: {
    allUsers() {
      return users;
    },
  },
  
  User: {
    fullName(root) {
      console.log(root); // { id: '1', firstName: 'Kim', lastName: 'YoungGil' }
      return `${root.firstName} ${root.lastName}`;
    },
  },
};

 

 

Resolvers

How Apollo Server processes GraphQL operations

www.apollographql.com

 

 

RelationShip

Resolvers의 첫 번째 인자인 root를 이용해서 RelationShip을 설정할 수 있습니다.

 

const tweets = [
  {
    id: '1',
    text: 'first one!',
    userId: '2',
  },
  {
    id: '2',
    text: 'second one',
    userId: '1',
  },
];

const users = [
  {
    id: '1',
    firstName: 'Kim',
    lastName: 'YoungGil',
  },
];


const resolvers = {
  Query: {
  Tweet: {
    author({ userId }) { // 유저들에서 글쓴이의 아이디와 비교하여 동일한 아이디를 찾아 리턴함
      return users.find(user => user.id === userId);
    },
  },
  
  User: {
    fullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    },
  },
};

 

Documentaion

 

설명하고자 하는 타입 위에 """ 할 말 """을 하게 된다면 쉽게 문서화가 가능합니다.

 

const typeDefs = gql`
  """
  유저에 관한 타입 설명입니다
  """
  type User {
    id: ID
    firstName: String
    lastName: String
    fullName: String
  }

  type Tweet {
    id: ID!
    text: String
    author: User
  }

  type Query {
    """
    모든 트위터에 대한 설명입니다
    """
    allTweets: [Tweet]
    tweet(id: ID): Tweet
    allUsers: [User]
  }

  type Mutation {
    postTweet(userId: ID, text: String): Tweet
    deleteTweet(id: ID): Tweet
  }
`;

 

 

REST API  --> graphQL로 변환하기

이 사이트에서 쉽게 변환할 수 있습니다. 타입을 graphQL으로 지정한 뒤 resolver을 사용해 활용하면 됩니다.

 

 

type Query {
    allMovies: [Movie!]!
    allUsers: [User!]!
    allTweets: [Tweet!]!
    tweet(id: ID!): Tweet
    movie(id: String!): Movie
  }


///

resolver .

{
    allMovies() {
      return fetch("https://yts.mx/api/v2/list_movies.json")
        .then((r) => r.json())
        .then((json) => json.data.movies);
    },
    movie(_, { id }) {
      return fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
        .then((r) => r.json())
        .then((json) => json.data.movie);
    },
}

 

JSON to GraphQL

Cadence struct to Go struct

transform.tools

 


 

22년도 요가 사용 방법

yarn add graphql-yoga

https://www.npmjs.com/package/graphql-yoga

 

graphql-yoga

Fully-featured GraphQL Server with focus on easy setup, performance & great developer experience. Latest version: 1.18.3, last published: 3 years ago. Start using graphql-yoga in your project by running `npm i graphql-yoga`. There are 111 other projects in

www.npmjs.com

 

 

CRA로 리액트 프로젝트를 만들듯이 graphql 프로젝트를 쉽게 사용하도록 도와주는 라이브러리입니다.

 

 

Schema

컴퓨터 과학에서 데이터베이스 스키마는 데이터베이스에서 자료의 구조, 자료의 표현 방법, 자료 간의 관계를 형식 언어로 정의한 구조이다.

 

shema.graphql 파일을 만들어서 타입 스크립트에서 interface를 만드는 것처럼 type 지정을 해주어야 합니다.

 

type Person {
  id: Int!
  name: String!
  age: Int!
  gender: String!
}

type Query {
  people: [Person]!
  person(id: Int!): Person
}

 

 

Resolvers

Apollo Server는 스키마의 모든 필드에 데이터를 채우는 방법을 알고 있어야 데이터 요청에 응답할 수 있습니다. 이를 위해 리졸버를 사용합니다.

리졸버는 스키마의 단일 필드에 대한 데이터를 채우는 함수입니다. 백엔드 데이터베이스 또는 타사 API에서 데이터를 가져오는 등 사용자가 정의하는 모든 방법으로 데이터를 채울 수 있습니다.

 

요약하자면 어떤 데이터를 사용할지 정하는 방법입니다.

 

 

서버를 작동

import { GraphQLServer } from "graphql-yoga";
import resolvers from "./graphql/resolvers";
console.log("hi");

const server = new GraphQLServer({
  typeDefs: "graphql/schema.graphql",
  resolvers,
});
server.start(() => console.log("Server is running on localhost:4000"));

 

 

localhost:4000에서 playground graphQL을 사용할 수 있습니다.

 

graphQl의 장점으로는 query 하나만으로 원하는 데이터를 가져올 수 있다는 점입니다.

 

 

 

원하는 정보 조회

원하는 아이디를 찾아서 조회할 수 있습니다.

import { people } from "../db/db";

const getById = (id) => {
  const person = people.filter((item) => item.id === id);
  return person[0];
};

const resolvers = {
  Query: {
    people: () => people,
    person: (_, { id }) => getById(id),
  },
};

export default resolvers;

 

 

Mutation

GraphQL에 대한 대부분의 논의는 데이터 취득에 초점을 맞추고 있지만 완전한 데이터 플랫폼에는 서버 측 데이터도 수정할 수 있는 방법이 필요합니다.

REST에서는 어떤 요구도 서버에 부작용을 일으킬 수 있지만, 관례상 GET 요청을 사용하여 데이터를 수정하지 않는 것이 좋습니다. GraphQL은 비슷합니다. 기술적으로는 데이터 쓰기를 유발하기 위해 어떤 쿼리도 구현할 수 있습니다. 그러나 쓰기를 유발하는 모든 작업은 변환을 통해 명시적으로 전송해야 한다는 규칙을 설정하는 것이 유용합니다.

쿼리와 마찬가지로 변환 필드가 개체 유형을 반환하는 경우 중첩된 필드를 요청할 수 있습니다. 이 기능은 업데이트 후 개체의 새 상태를 가져올 때 유용합니다. 

 

API를 이용할 때 새로운 데이터를 추가하거나 삭제, 수정해야 할 경우가 있는데 이럴 때 사용 가능한 것이 Mutation입니다.

 

 

addMovie는 함수로 만들어서 사용합니다. API 관리하는데 엄청 편한 것 같습니다.

 

let movies = [
  {
    id: 0,
    name: "Star Wars - The new one",
    score: 1,
  },
  {
    id: 1,
    name: "Avengers - The new one",
    score: 8,
  },
  {
    id: 2,
    name: "The Godfather I",
    score: 99,
  },
  {
    id: 3,
    name: "Logan",
    score: 2,
  },
];

export const getMovies = () => movies;

export const getById = (id) => {
  const filteredMovies = movies.filter((movie) => movie.id === id);
  return filteredMovies[0];
};

export const deleteMovie = (id) => {
  const cleanedMovies = movies.filter((movie) => movie.id !== id);
  if (movies.length > cleanedMovies.length) {
    movies = cleanedMovies;
    return true;
  } else {
    return false;
  }
};

export const addMovie = (name, score) => {
  const newMovie = {
    id: `${movies.length + 1}`,
    name,
    score,
  };
  movies.push(newMovie);
  return newMovie;
};

 

 

이름과 스코어를 입력하여 추가함

 

짜장면을 추가하는 모습
데이터에 짜장면이 추가된 모습

 

GraphQL을 사용해 보니 기존의 REST API에서 사용했었던 방식이 조금 불편해지지 않을까라고 생각이 되고 그만큼 잘 개발되어 만들어진 것 같다고 느꼈습니다. 앞으로 개인적인 프로젝트가 있다면 GraphQL방식을 사용해 볼 것 같습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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
글 보관함