TIL_GraphQL

박성훈·2022년 10월 5일
0

백엔드

목록 보기
12/13
post-thumbnail

💡GraphQL

Graph + Query Language

우리가 REST API를 사용하여 데이터를 받아올 때는,

{
	"user" : {
    	"id" : "fasefes"
        "name" : "hun",
        "address" : {...},
        "birthday" : "July 12. 1998"
    }
}

이렇게 요청한 데이터는 우리가 원하는 정보외에도 불필요한 정보까지 포함하고 있다.
또한, server URI의 엔드포인트에서 우리가 원하는 정보를 한번에 충분히 제공하지 못한다.

예를 들어, 서버의 엔드포인트가 다음과 같이 나눠져 있을 때,

localhost:3000

localhost:3000/title

localhost:3000/description

각각의 엔드포인트에서 해당하는 정보가 제공될 것이고, 우리는 원하는 정보를 모두 받아오기 위해, 각각의 엔드포인트에 모두 요청을 보내야된다.

이런 비효율적인 측면을 해결하기위해 GraphQL이 등장하게 된다.


GraphQL은 /graphql 이라는 단 하나의 엔드포인트로 요청과 응답을 주고받는다.
즉, Rest API처럼 여러 엔드포인트로 요청하는 것이 아니라, 하나의 엔드포인트에서 쿼리를 이용해 원하는 데이터를 받을 수 있다.

🔍 GraphQL 구조

📌 쿼리 (Query)

필드

{
	hero {
    	name
    }
}

클라이언트에서 hero의 name을 검색하기위한 쿼리를 서버에 요청하게된다면

{
	"data" : {
    	"hero" : {
    		"name" : "R2-D2"
 	   }
    }
}

서버는 클라이언트가 요청한 필드와 똑같은 형태로 돌려주게 된다.

즉, GraphQL은 클라이언트 요청에 따라 유연하게 트리구조의 JSON 데이터를 응답으로 전송해준다.

트리구조의 JSON데이터를 응답으로 전송하는 이유는
GraphQL은 모든 데이터가 그래프의 형태로 되어있다고 전제한다는 점에 시작된다.


위와 같이 데이터가 연결되어있다고 했을 때, 그래프안에서 우리는 누구를 기준으로 잡냐에 따라 트리구조로 변환시킬 수 있다.

User에 대한 정보를 서버에 요청했을 때, 서버는

{
	"User" : {
    	"Address" : ...,
        "E-mail" : ...,
        "Friends" : ...,
        "Study" : {
        	"University" : ...,
            "Professor" : ...
        }
        
    }
}

위와 같은 JSON형태로 응답해준다.

즉, 클라이언트가 어떤 정보를 요청했는지에 따라 유연하게 트리구조의 데이터를 보내줄 수 있다.

또한, 그래프 형태의 데이터를 트리구조로 변환하기때문에, 관련 객체 및 필드를 순회할 수 있다.

그렇기 때문에, 다양한 엔드포인트를 만들어 각기 요청을 보내는 것이 아닌, 하나의 요청을 보냄으로써 관련 데이터를 가져올 수 있는 것이다.


📌 전달인자 (Arguments)

필드에 전달인자를 추가하면, 전달인자에 만족하는 데이터만 받아올 수 있다.

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

human중 id가 3000에 해당하는 human의 name, height를 받아온다.


📌 별명(Aliases)

GraphQL은 필드이름을 중복해서 사용할 수 없다.
그렇기 때문에, 같은 필드이름으로 여러 데이터를 한번에 받아오고싶다면,

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

이런식으로 필드명 앞에 별명을 붙여줄 수 있다.

{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"
    }
  }
}

서버에서는 위와 같이 데이터를 보내준다.


📌 오퍼레이션 네임(Operation name)

우리가 함수를 작성하는 것처럼 작성쿼리에 대한 오퍼레이션 타입과 name을 앞에 작성해준다.

query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}

🪄오퍼레이션 타입

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

📌 변수(Variables)

고정된 인수가 아닌 동적으로 인수를 받아 쿼리하는 경우에 변수를 사용한다.

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

'$변수이름 : 타입' 형태로 정의한다.
만약 타입뒤에 ! 가 붙는다면 해당 변수는 반드시 해당 타입이어야한다는 뜻이다.


📌 뮤테이션 (mutation)

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

mutation이라고 오퍼레이션 타입으로 명시해주면, 데이터를 수정, 삭제, 생성 할 수 있다.


📌 스키마/타입(Schema/Type)

type Character {
  name: String!
  appearsIn: [Episode!]!
}

데이터에 대해 정의한다고 생각하면 된다.
Character라는 데이터의 이름은 반드시 문자열로 구성되어야하고, 반드시 0개 이상의 Episode요소를 가지고 있다는 뜻이다.


📌 리졸버(Resolver)

Query, Mutation, Subscription을 모아놓은 함수를 말한다.

const db = require("./db")
const resolvers = {
	Query : {
    	...
    },
    Mutation : {
    	...
    },
    Subscription : {
    	...
    }
}

Resolver함수를 통해 데이터를 가져오는 구체적인 과정을 직접 구현할 수 있다.

profile
프론트엔드 학습일지

0개의 댓글

관련 채용 정보