REST API 너무 지저분해!

김민국·2021년 7월 20일
0

0. 목표

YTS API(영화 정보 알려주는 API)를 GraphQL로 wrapping하여 API 요소 중 원하는 정보만 받아올 수 있도록 만드는 것이다.
API 구조 미리보기: https://yts.mx/api/v2/list_movies.json?
github: https://github.com/MinGookK/movieql


무슨 말인지 모르겠다면 이전 포스팅을 보고 오자 30초면 읽는다.

GraphQL을 써야하는 이유?


들어가기 앞서 포스팅은 GraphQL을 깊게 다루지는 않는다.

1. 구조

GraphQL으로 API 를 만드는데에는 크게 4가지 파일로 나누어진다.

  1. index.js
    서버 구동 코드를 작성한다.

  2. schema.graphql
    GraphQL의 Data type을 명시한다.
    (데이터의 요청, 변형을 요청하는 type. 그에따른 결과의 type을 명시)

  3. resolvers.js
    schema를 바탕으로 실제로 데이터가 어떻게 움직일지를 작성해줌
    (schema = 문제집, resolvers = 해답지)

  4. db.js
    data와 관리하는 함수 등을 작성.

1. index.js

여기서는 graphql 서버 구동 코드를 작성한다.

import { GraphQLServer } from 'graphql-yoga';
import resolvers from './graphql/resolvers';

//GraphQLServer 안의 {} 에 서버 환경설정을 넣어주면 서버 구동 끝이다. 너무 쉽다.
const server = new GraphQLServer({
  //모든 type에 대한 정의임 작성해둔 graphql의 위치 입력
  typeDefs: 'graphql/schema.graphql',
  resolvers,
});

server.start(() => console.log('GraphQL Server Running'));

별게 없다. 이게 서버 구동의 끝이다. ㅋㅋㅋ
GraphQLServer 안에 2,3 요소인 schema와 resolvers를 넣어주면 된다.

이게 뭔지는 알려줄테니 계속 읽어보자.

2. schema.graphql

여기서는 GraphQL API에서 사용할 data type들을 명시하는 곳이다.

type Movie {
  #첫줄 설명: id라는 것은 Int 자료형을 가지고 "반드시 필요"(!)하다.
  #반드시 필요하지 않은 값이라면 !를 빼주면 된다.
  id: Int!
  title: String!
  rating: Float!
  summary: String!
  medium_cover_image: String!
}

type Query {
  # person이라는 쿼리를 담아 보내면 String 형태로 반환해 줄 것이고 반드시 필요하다(!)라는 뜻
  movies(limit: Int, rating: Float): [Movie]!
}

API 미리보기 링크를 클릭해보면 한 영화에 대해 엄청나게 많은 정보가 받아진다.

우리는 이 중에서
id, title, rating, summary, medium_cover_image
만 필요할 것 같기 때문에 type Movie에 해당 파라미터만 타입을 표기해준다.

그리고 Query를 통해 movies를 부르면, 결과에 맞는 Movie들의 Array를 반환할 것이다.

3.resolvers.js

schema에서 query를 어떻게 담을 것이고, 결과는 어떤 type이 될 지를 명시해 주었다.

이제는 진짜 데이터가 어떻게 받아와질지, 해답지를 작성해주면 된다.

// Query를 resolve(해결)하는 것
// graphql 에서 작성한 쿼리를 해결하는 코드를 resolvers에서 작성한다.

import { getMovies } from './db';

const resolvers = {
  Query: {
    movies: (_, { limit, rating }) => getMovies(limit, rating),
  },
};

export default resolvers;

movies( _, { limit, rating } )에서 _ 은 root인데 여기서는 필요 없다.

사용자로부터 limit와 rating을 받아와서
getMovies에서 limit 개수만큼의 rating 이상의 별점을 받은 영화만 반환하도록 해준 것이다.

이러면 resolvers도 끝났다.

4. db.js

이제 type 정의와 resolver까지 모두 완료했다.
이제 getMovies가 어떻게 영화 정보를 받아오는지만 작성해주자.

import axios from 'axios';

export const getMovies = (limit, rating) => {
  let API_URL = 'https://yts.mx/api/v2/list_movies.json?';
  if (limit > 0) {
    API_URL += `limit=${limit}`;
  }
  if (rating > 0) {
    API_URL += `&minimum_rating=${rating}`;
  }
  return axios.get(API_URL).then((res) => res.data.data.movies);
};

API Document: https://yts.mx/api#list_movies

도큐먼트 읽어보면 알겠지만 limit을 입력해주면 그 숫자만큼 영화를 불러와주고,
minimum_rating을 입력해주면 입력한 수 이상의 평점을 받은 영화만 불러와준다.

이제 끝났다! 테스트 해보자.

2. 테스트

GraphQL yoga를 사용하면 이렇게 생성한 API를 아주 쉽게 테스트 해볼 수 있다.
yarn start로 실행하고 localhost:4000을 주소창에 입력해보자.

여기서 우리가 만든 API를 테스트 해볼 수 있다. 오른편에 DOCS 버튼을 눌러보자.

놀랍게도 우리가 schema에 작성한 내용이 보기좋게 정리되어 있다.
시키는 대로 Query를 작성해보자.

테스트가 잘 진행되었는지 보기 위해 title과 rating만 표기하도록 호출을 해 보았다.

예상대로 limit 숫자인 4개의 정보가 들어왔고 rating도 다들 8점이 넘는 것을 볼 수 있다.

예시로 title과 rating만 표기하도록 만들었지만, 이 외에도 필요한 정보를 얼마든지 추가하거나 빼서 호출을 하면 "딱" 요청한 정보만 받아볼 수 있다.

영화 커버 이미지 정보를 추가로 받아보자.

역시 성공적으로 받아졌다!!

이런 데이터 정제 작업은 프론트에서 많이 처리하게 되었었는데,
애초에 API 설계를 GraphQL을 통해 하면 프론트에서는 display와 기능 구현에만 집중할 수 있게 되어 일이 훨씬 수월해질 수 있을 것 같다.

0개의 댓글