[강의노트] GraphQL로 영화 API 만들기

Tia Hwang·2020년 5월 6일
1

[Nomad] 강의노트

목록 보기
1/2

노마드코더의 무료강의 GraphQL로 영화 API 만들기 강의노트 ✏️

1. Set Up

  • yarn init
  • yarn add graphql-yoga

2. Why GraphQL?

2-1. Over-fetching

  • GET 방식으로 데이터를 요청하는 경우, 영화이름만 필요한 경우에도 영화이름 뿐만아니라 다른 정보들(포스터, 출시연도, 평점 등)을 같이 불러오게 되는 것
  • 사용하지 않을 정보까지 요청하게 됨 ➡️ 비효율적

2-2. Under-fetching

  • 어떤 하나를 완성하기 위해 다른 요청들을 해야할 때 발생

    GraphQL은 내가 원하는 정보들만 불러올 수 있음❗
    위의 2가지 문제 모두 해결가능

3. Create GraphQL Server

  • nodemon 글로벌하게 설치하기: yarn global add nodemon
    ➡️ 파일 수정시, 자동으로 서버 재시작해줌

여기서 잠시❗ 신식(?)코드를 사용하기 위한 babel 셋업 😃

  • yarn add babel-node --dev
  • yarn global add babel-cli --ignore-engines
  • yarn add babel-cli babel-preset-env babel-preset-stage-3 --dev
  • .babelrc 파일 생성 후, {"presets": ["env", "stage-3"]} 설정
  • (package.json)
"scripts": {
    "start": "nodemon --exec babel-node index.js"
}
  • (index.js)
import { GraphQLServer } from "graphql-yoga";

const server = new GraphQLServer({});

server.start(() => console.log("GraphQL server is RUNNING"));

서버 세팅 끝!
지금 상태에서 schema 블라블라 오류가 나오는 건 정상!

4. Create Query and Resolver

  • schema: description of data that I will get or send
  • query: only used when I get the data
  • mutation: when I change/mutate the data
  • graphql 폴더 > schema.graphql 파일 생성
type Query {
    name: String!
}

여기서 설정한 Query는 JSON data 같은 것이라고 보면 됨
끝에 !(느낌표) = isRequired

GraphQL playground에서 name에 String이 아닌 예를들어 숫자가 입력된 경우 에러메세지가 뜸! 어메이징 🤓

  • graphql 폴더 > resolvers.js 파일 생성
const resolvers = {
    Query: {
        name: () => "tia",
    },
};

export default resolvers;
  • (index.js)
import resolvers from "./graphql/resolvers";

const server = new GraphQLServer({
    typeDefs: "graphql/schema.graphql",
    resolvers,
});

localhost:4000 으로 접속! GraphQL playground가 나옴 🥰
GraphQL playground는 graphql-yoga에서 실행되는 것. database를 테스트하게 해줌!

5. Extend the Schema

5-1. 기초

  • (resolvers.js)
const tia = {
    name: "Tia",
    age: "24",
    gender: "female",
};

const resolvers = {
    Query: {
        person: () => tia,
    },
};
  • (schema.graphql)
type Tia {
    name: String!
    age: Int!
    gender: String!
}

type Query {
    person: Tia!
}
  • GraphQL playground에서 내가 원하는 정보만 불러올 수 있음

5-2. 심화

  • db.js 파일 생성
export const people = [
    { id: "0", name: "Tia", age: "24", gender: "female" },
    { id: "1", name: "Rui", age: "18", gender: "female" },
    { id: "2", name: "Dubu", age: "30", gender: "female" },
    { id: "3", name: "Terry", age: "30", gender: "male" },
    { id: "4", name: "Eunice", age: "22", gender: "female" },
];

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

filteredPeople[0]으로 쓰는 이유
➡️ Because array.filter returns an array with the elements that match the condition. As we find an element with an ID then .filter will return an array with only one element, that's why we do [0] since we want the first and only element.

  • (resolvers.js)
import { people, getById } from "./db";

const resolvers = {
    Query: {
        people: () => people,
        person: (_, { id }) => getById(id),
    },
};
  • (schema.graphql)
type Person {
    id: Int!
    name: String!
    age: Int!
    gender: String!
}

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

6. Create Mutation

6-1. Add Movie

  • (schema.graphql)
type Mutation{
    addMovie(name: String!, score: Int!): Movie!
}
  • (db.js)
let movies = [
    { id: 0, name: "star wars", score: 0.2,},
    { id: 1, name: "A", score: 8,},
    { id: 2, name: "The", score: 89,},
    { id: 3, name: "M", score: 5,},
];

export const addMovie = (name, score) => {
    const newMovie = {
        id: `${movies.length + 1}`,
        name,
        score,
    };
    movies.push(newMovie);
    return newMovie;
};
  • (resolvers.js)
import { getMovies, getById, addMovie } from "./db";

const resolvers = {
    ~
    Mutation: {
        addMovie: (_, { name, score }) => addMovie(name, score),
    },
};

playground에서 movies를 쳐보면 "parents"가 추가되어 있음

6-2. Delete Movie

  • (schema.graphql)
type Mutation {
    ~
    deleteMovie(id: Int!): Boolean!
}
  • (db.js)
export const deleteMovie = (id) => {
    const cleanedMovies = movies.filter((movie) => movie.id !== id);
    if (movies.length > cleanedMovies.length) {
        movie = cleanedMovies;
        return true;
    } else {
        return false;
    }
};
  • (resolvers.js)
import { ~, addMovie, deleteMovie } from "./db";

const resolvers = {
    ~
    Mutation: {
        addMovie: (_, { name, score }) => addMovie(name, score),
        deleteMovie: (_, { id }) => deleteMovie(id),
    },
};

7. REST API with GraphQL

  • yarn add node-fetch
    ➡️ Node.js에서 fetch 할때 필요
  • (db.js)
import fetch from "node-fetch";

const API_URL = "https://yts.am/api/v2/list_movies.json";

export const getMovies = (limit, rating) =>
    fetch(`${API_URL}`)
        .then((res) => res.json())
        .then((json) => json.data.movies);
  • (schema.graphql)
type Movie {
    id: Int!
    title: String!
    rating: Float!
    summary: String!
    language: String!
    medium_cover_image: String!
}

type Query {
    movies: [Movie]!
}

"https://yts.am/api/v2/list_movies.json"의 형태에 따라서 query 정의

  • (resolvers.js)
import { getMovies } from "./db";

const resolvers = {
    Query: {
        movies: () => getMovies(),
    },
};
profile
프론트엔드 개발자로 취업하기

0개의 댓글