Daily Front_Minhhk

Graph QL 본문

Code개발일지

Graph QL

Minhhk 2023. 1. 31. 21:42

GraphQL

Graph + Query Language

Query Language 중에서도 Server API 를 통해 정보를 주고받기 위해 사용하는 Query Language를 뜻하며,API를 위한 쿼리 언어라고 할 수 있습니다.

GraphQL은 트리 구조로 쿼리 결과를 받기 위해 그래프를 탐색하는 쿼리 언어라고 볼 수 있습니다.

 

GraphQL의 특징

  • GraphQL은 HTTP를 통해 API 서버로 요청을 보내고 응답을 받습니다.
  • 응답을 받을 시, 데이터 결과를 JSON 형식으로 받습니다.
  • GraphQL은 서버 개발자가 작성한 각 필드에 대응하는 resolver 함수로 각 필드의 데이터를 조회할 수 있습니다.
  • GraphQL은 GraphQL 라이브러리가 조회 대상 schema가 유효한지 검사합니다.

 

GraphQL의 장점

  • 하나의 endpoint 요청
    • /graphql이라는 하나의 endpoint 로 요청을 받고 그 요청에 따라 query , mutation을 resolver 함수로 전달해서 요청에 응답합니다. 모든 클라이언트 요청은 POST 메소드를 사용합니다.
  • No! under & overfetching
    • 여러 개의 endpoint 요청을 할 필요없이 하나의 endpoint에서 쿼리를 이용해 원하는 데이터를 정확하게 API에 요청하고 응답으로 받을 수 있습니다.
  • 강력한 playground
    • graphql 서버를 실행하면 playground라는 GUI를 이용해 resolverschema 를 한 눈에 보고 테스트 해 볼 수 있습니다. (POSTMAN 과 비슷합니다.)
  • 클라이언트 구조 변경에도 지장이 없음
    • 클라이언트 구조가 바뀌어도 필요한 데이터를 결정하고 받는 주체가 클라이언트이기 때문에 서버에 지장이 없습니다. 클라이언트에서는 무슨 데이터가 필요한 지에 대해서만 요구사항을 쿼리로 작성하면 됩니다.

 

GraphQL의 단점

  • REST API에 친숙한 개발자의 경우 GraphQL를 학습하는 데 시간이 필요합니다.
  • 캐싱이 REST보다 훨씬 복잡합니다.
    • HTTP에선 각 메소드에 따라 캐싱이 구현되어 있습니다. 하지만 GraphQL에선 POST 메소드만을 이용해 요청을 보내기 때문에 각 메소드에 따른 캐싱을 지원받을 수 없습니다. 그래서 이를 보완하기 위해 Apollo 엔진의 캐싱과 영속 쿼리 등이 등장하게 되었습니다.
  • 고정된 요청과 응답만 필요할 경우에는 Query 로 인해 요청의 크기가 RESTful API 의 경우보다 더 커집니다.

 

REST API의 한계

  • Overfetch : 필요 없는 데이터까지 제공함
  • Underfetch: endpoint 가 필요한 정보를 충분히 제공하지 못함
  • 클라이언트 구조 변경 시 엔드포인트 변경 또는 데이터 수정이 필요함
    • REST API에서는 자원의 크기와 형태를 서버에서 결정하기 때문에 클라이언트가 직접 데이터의 형태를 결정할 수 없습니다. 이로 인해 만약 클라이언트에서 필요한 데이터의 내용이 변할 경우 다른 endpoint를 통해 변경된 데이터를 가져오거나 수정을 해야합니다.

 

 

REST API와 GraphQL의 다른점

REST API는 Resource에 대한 형태 정의와 데이터 요청 방법이 연결되어 있지만,
GraphQL에서는 Resource에 대한 형태 정의와 데이터 요청이 완전히 분리되어 있습니다.
REST API는 Resource의 크기와 형태를 서버에서 결정하지만,
GraphQL에서는 Resource에 대한 정보만 정의하고, 필요한 크기와 형태는 클라이언트 단에서 요청 시 결정합니다.
REST API는 URI가 Resource를 나타내고 Method가 작업의 유형을 나타내지만,
GraphQL에서는 GraphQL Schema가 Resource를 나타내고 Query, Mutation 타입이 작업의 유형을 나타냅니다.
REST API는 여러 Resource에 접근하고자 할 때 여러 번의 요청이 필요하지만,
GraphQL에서는 한번의 요청에서 여러 Resource에 접근할 수 있습니다.
REST API에서 각 요청은 해당 엔드포인트에 정의된 핸들링 함수를 호출하여 작업을 처리하지만,
GraphQL에서는 요청 받은 각 필드에 대한 resolver를 호출하여 작업을 처리합니다.

 

 

GraphQL 구조

  • Query: 저장된 데이터 가져오기 (REST의 GET과 비슷합니다.)
  • Mutation: 저장된 데이터 수정하기
    • Create: 새로운 데이터 생성
    • Update: 기존의 데이터 수정
    • Delete: 기존의 데이터 삭제
  • Subscription: 특정 이벤트가 발생 시 서버가 대응하는 데이터를 실시간으로 클라이언트에게 전송

 

 

쿼리(데이터 조회)

필드 field
매우 간단한 query(데이터 조회, 이하 쿼리)와 실행 했을 때 얻은 결과

{
  hero {
    name
    # 이런 식으로 GraphQL 내에서 주석도 작성할 수 있습니다.
    friends {
      name
    }
  }
}
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

전달인자 Arguments

필드에 인수를 전달하는 부분을 추가하면 쿼리의 필드 및 중첩된 객체들에 전달해 원하는 데이터만 받을 수 있다.

{
  human(id: "1000") {
    name
    height
  }
}

별명 Aliases

필드 이름을 중복해서 사용할 수 없다. 필드 이름을 중복으로 사용해서 쿼리를 해야 할 때에는 별명을 붙이면 된다.

{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}

오퍼레이션 네임 Operation name

약식으로 작성하지 않는 한 반드시 필요하다.
타입의 종류에는 query, mutation, subscription, describes 등등 있다.

// query 가 오퍼레이션 네임!
query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}

변수 Variables

오퍼레이션 네임 옆에 변수를 $변수이름:타입 이런식으로 정의.
뒤에 !가 붙기도 한다.($ep: Episode! 일때 ep는 반드시 Episode여야한다는 의미)

query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}




뮤테이션 mutation(데이터 수정)

GraphQL은 대개 데이터를 가져오는 데에 중점을 두고 있지만 서버측 데이터를 수정하기도 합니다.

REST API에서 GET 요청을 사용하여 데이터를 수정하지 않고, POST 혹은 PUT 요청을 사용하는 것처럼 GraphQL도 유사하며,

GraphQL은 mutation이라는 키워드를 사용하여 서버 측 데이터를 수정합니다.

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}



스키마/타입 Schema/Type

구성요소: 객체의 종류, 객체 유형

type Character {
  name: String!
  appearsIn: [Episode!]!
}
  • Character : GraphQL객체타입. 필드가 있는 타입.
    스키마에 있는 대부분의 타입은 객체타입이다.
  • name과 appearIn은 Character 타입의 필드.
  • String은 내장된 스칼라 타입.
    스칼라 타입: ID, Int, String, Float, Boolean
  • !가 붙는다면 null이 아니어야 한다는 의미.
  • []는 배열을 의미한다.


리졸버 Resolver

요청에 대한 응답을 결정해주는 함수로써

GraphQL의 여러 가지 타입 중 Query, Mutation, Subscription과 같은 타입의 실제 일하는 방식 즉 로직을 작성한다.

스키마를 정의하면 그 스키마 필드에 사용되는 함수의 실제 행동을 Resolver에서 정의한다.

const db = require("./../db")
const resolvers = {
  Query: { // **Query :** 저장된 데이터 가져오기 (REST 에 GET 과 비슷합니다.)
	getUser: async (_, { email, pw }) => {
		db.findOne({
			where: { email, pw }
		}) ... // 실제 디비에서 데이터를 가져오는 로직을 작성합니다.
		...
	}
  },
  Mutation: { // **Mutation :** 저장된 데이터 수정하기 ( Create , Update , Delete )
	createUser: async (_, { email, pw, name }) => {
		...
	}
  }
  Subscription: { // **Subscription :** 실시간 업데이트
    newUser: async () => {
      ...
	}
  }
  
};



 

'Code개발일지' 카테고리의 다른 글

Optimization 최적화  (0) 2023.02.01
TDD(Test-driven Development)  (0) 2023.01.31
컴퓨터 공학 - 구조, 운영체제  (0) 2023.01.27
React.lazy()와 Suspense  (0) 2023.01.26
Custom Hooks  (0) 2023.01.25