GraphQL로 영화 API 만들기

    0. Introduction

    • GraphQL

    • Graphile

      • Graphile은 GraphQL API를 자동으로 생성하기 위한 도구와 라이브러리의 집합이다. Graphile을 사용하면 데이터베이스 스키마로부터 GraphQL API를 생성할 수 있다.
      • Graphile은 데이터베이스 스키마로부터 자동으로 GraphQL API를 생성하는 강력하고 유연한 도구이다. 이를 통해 개발자들은 빠르고 효율적으로 GraphQL 서버를 구축하고 데이터베이스와의 상호작용을 간단하게 관리할 수 있다.
      • https://www.graphile.org/
    • Hasura

      • Hasura는 기존 데이터베이스에서 즉각적으로 GraphQL API를 무료로 만들어준다.
      • https://hasura.io/

    1. GraphQL이 해결하는 문제점

    Overfetching

    Overfetching 필요한 데이터보다 더 많은 데이터를 fetch하는 것을 말한다. 이러면 백엔드나 데이터베이스가 일을 더 많이 해야 해서 데이터 전송이 느려질 수 있다.

    GraphQL은 url로 데이터를 즉시 받지 않는다. 대신, 필요한 데이터를 요청한다.

    GraphQL을 사용하면 클라이언트에서 API에 GraphQL 쿼리를 보내고 필요한 것만 정확히 얻을 수 있다.

    Underfetching

    필요한 데이터보다 적은 데이터가 fetch되는 것을 말한다.

    일반적인 REST API는 이러한 경우 여러 URL을 사용하여 필요한 데이터들을 가져와야 하지만, GraphQL API는 앱에 필요한 모든 데이터를 단일 요청으로 가져올 수 있다. 이를 통해, GraphQL을 사용하는 앱은 느린 모바일 네트워크 연결에서도 빠를 수 있다.

    2. 환경설정

    Apollo Server

    Apollo 서버는 Apollo 클라이언트를 포함한 모든 GraphQL 클라이언트와 호환되는 사양을 준수(spec-compliant)하는 오픈 소스 GraphQL 서버이다. 모든 소스의 데이터를 사용할 수 있고, 자체 문서화가 가능하며, 프로덕션에서 사용 가능하다.

    https://www.apollographql.com/docs/apollo-server/

    https://www.apollographql.com/docs/apollo-server/getting-started/

    • apollo-server와 graphql 설치
    npm install apollo-server graphql

    Nodemon

    • Nodemon은 Node.js 개발 시 유용한 도구로, 파일 변경 감지를 통해 자동으로 서버를 재시작해주는 도구이다.
    npm install nodemon -D
    // 스크립트
    "dev": "nodemon server.js"

    graphQl 구문 하이라이팅 vscode 익스텐션

    3. GraphQL 스키마 정의

    모든 GraphQL 서버(아폴로 서버)는 클라이언트가 쿼리 요청할 수 있는 데이터의 구조를 정의하는 스키마를 사용한다.

    Query 타입

    Query 타입은 GET 요청을 만드는 것과 같으며 필수이다.

    • 아폴로 서버를 실행하기 위해서는 반드시 최소 1개의 Query가 필요하다. type Query는 가장 기본적인 타입입니다. Query에 넣는 필드들은 request할 수 있는 것들이 된다.

    Mutation 타입

    Mutation 타입은 POST, PUT, DELETE 와 같이 서버 측 데이터를 수정할 수 있는 방법이다. 서버 측 데이터를 수정하는 모든 작업은 mutation을 통해 보내야 한다는 규칙을 설정하는 것이 유용하다.

    import { ApolloServer, gql } from "apollo-server"
    
    // GET /api/tweets
    // GET /api/tweets/:id
    // POST /api/tweets
    
    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(text: String, userId: ID): Tweet
    	}
    `
    
    const server = new ApolloServer({ typeDefs })
    
    server.listen().then(({ url }) => {
    	console.log(`Running on ${url}`)
    })
    // 쿼리 요청 시 mutation 을 앞에 붙여야 한다
    mutation {
      postTweet(text: "HELLO", userId: "2") {
        text
      }
    }

    4. 타입

    Scalar

    Scalar 타입은 GraphQL 스키마에서 사용되는 기본 데이터 타입이다. Scalar 타입은 단일 값으로 표현되는 데이터를 나타내며, GraphQL에는 다양한 내장 Scalar 타입이 있다.

    내장 Scalar 타입은 다음과 같다.

    1. Int: 32비트 정수로 표현되는 숫자
    2. Float: 부동 소수점 숫자로 표현되는 실수
    3. String: 유니코드 문자열
    4. Boolean: true 또는 false 값을 가지는 논리 타입
    5. ID: 고유한 식별자로 사용되는 문자열이며, 주로 데이터베이스의 기본 키와 매핑됨

    Non-Nullable

    타입에 !를 붙이면 Non-Nullable이다.

    Non-Nullalbe은 서버가 항상 이 필드에 대해 null이 아닌 값을 반환할 것으로 기대한다. 즉, !가 붙지 않은 필드는 nullable field(null값을 가질 수 있는 필드)이다.

    https://graphql.org/learn/schema/#lists-and-non-null

    5. Resolvers

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

    resolver 함수는 field가 요청했을 때 실제로 호출될 함수이다.

    // args는 GraphQL 쿼리의 필드에 제공된 인수
    const resolvers = {
    	Query: {
    		allTweets() {
    			console.log("트윗을 가져옵니다")
    			return tweets
    		},
    		tweet(root, args) {
    			return tweets.find(tweet => tweet.id === args.id)
    		},
    	},
    }

    https://graphql.org/learn/execution/#root-fields-resolvers

    Resolver arguments

    Resolver 함수에는 parent(root or source), args, context, info 의 네 가지 인수가 순서대로 전달된다.

    https://www.apollographql.com/docs/apollo-server/data/resolvers/#resolver-arguments

    Type Resolvers

    type User의 fullName에 대한 resolver를 만들 수 있다

    const typeDefs = gql`
    	type User {
    		id: ID
    		firstName: String!
    		lastName: String!
    		fullName: String
    	}
    `
    
    const resolvers = {
    	User: {
    		fullName({ firstName, lastName }) {
    			// type User의 fullName에 대한 resolver
    			return `${firstName} ${lastName}`
    		},
    	},
    }

    6. 문서화

    https://www.apollographql.com/docs/resources/graphql-glossary/#docstring

    타입, 필드 또는 인자에 대한 설명을 제공한다. Docstring은 Apollo Studio Explorer를 비롯한 많은 일반적인 GraphQL 클라이언트 도구에서 자동으로 문서화되어 표시된다.

    """
    Description for the User
    """
    type User {
      """
      Description for first Name
      """
      firstName: String!
    
      age(
        """
        Must be an integer
        """
        arg: Int
      )
    }

    7. Subscription Type

    Subscription을 사용하면 클라이언트는 서버로부터 실시간으로 변경되는 데이터를 받을 수 있으므로, 애플리케이션의 실시간 업데이트나 상호 작용성을 구현하는 데 유용하다.


    Written by@Marco

    GitHub