GraphQL

jindory·2022년 8월 2일
1

GraphQL 이란?

GraphQL은 페이스북에서 만든 쿼리 언어
GraphQL에서는 모든 데이터가 그래프 형태로 연결되어 있다고 전제한다. 트리나 그래프나 노드와 노드를 연결하는 간선으로 구성된 자료구조이기 때문. 이를 통해 GraphQL은 클라이언트 요청에 따라 유연하게 트리 구조의 JSON 데이터를 응답으로 전송할 수 있다. REST API 방식의 고정된 자원이 아닌 클라이언트 요청에 따라 유연하게 자원을 가져올 수 있다는 점에서 이점을 갖고있다.

GraphQL의 특징

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

REST API와 GraphQL의 다른점

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

GraphQL로 Blog 앱을 구현할 때

//HTTP POST
query{
	User(id: "er3tgdjq"){
    	name
        posts{
        	title
        }
      	followers(last:3){
        	name
        }
    }
}
{
	"data":{
    	"User" : {
        	"name" : "Mary",
            "posts" : [
              {title : "..."},
              {title : "..."},
              {title : "..."},
              {title : "..."}
            ],
            "followers" : [
              {name : "John"},
              {name : "Alice"},
              {name : "Sarah"},
            ]
        }
    }
}
  • 하나의 endpoint 요청
    /graphql 이라는 하나의 endpoint로 요청을 받고 그 요청에 따라 query, mutation을 resolver 함수로 전달해서 요청에 응답
  • No! under & overfetching
    하나의 endpoint에서 쿼리를 이용해 원하는 데이터를 정확하게 API에 요청하고 응답으로 받을 수 있다.
  • 강력한 playground
    graphql 서버를 실행하면 playground라는 GUI를 이용해 resolver 와 schema를 한 눈에 보고 테스트 가능
  • 클라이언트 구조 변경에도 지장이 없음
    클라이언트 구조가 바뀌어도 필요한 데이터를 결정하고 받는 주체가 클라이언트이기 떄문에 서버에 지장이 없다. 유후유후후



GraphQL 구조

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

01.쿼리(query, 데이터 조회)

필드(field)

//히어로의 이름과 히어로의 친구 이름을 같이 쿼리
{
  hero {
    name
    # 이런 식으로 GraphQL 내에서 주석도 작성할 수 있습니다.
    friends {
      name
    }
  }
}

//히어로의 이름과 히어로의 친구의 이름이 조회되어 나옵니다.
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

전달인자(Arguments)

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

//id가 1000인 human의 name과 height를 쿼리
{
  human(id: "1000") {
    name
    height
  }
}

별명(Aliases)

필드 이름을 중복해서 사용할 수 없으므로, 필드 이름을 중복으로 사용해서 쿼리를 해야 할 때는 별명을 붙여서 쿼리한다.

//앞에 알아볼 수 있는 별명을 붙여주면 쿼리할 수 있습니다.
{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}

//쿼리 결과를 받아볼 수 있습니다.
{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"
    }
  }
}

오퍼레이션 네임(Operation name)

여태껏 쿼리와 쿼리 네임을 모두 생략하는 축약형 구문을 사용했습니다만, 실제 앱에서는 코드를 모호하지 않게 작성하는 것이 중요

//이런 식으로 query keyword와 query name을 작성합니다. 
query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}

변수(Variables)

오퍼레이션 네임 옆에 변수를 $변수 이름: 타입 형태 로 정의
위의 예시처럼 $ep: Episode 일 때, 뒤에 !가 붙는다면 ep는 반드시 Episode여야 한다는 뜻입니다. !는 옵셔널한 사항

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

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

POST 혹은 PUT 요청을 사용하는 것처럼 GraphQL도 유사합니다. GraphQL은 mutation이라는 키워드를 사용하여 서버 측 데이터를 수정

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

스키마/타입(Schema/Type)

GraphQL 스키마의 가장 기본적인 구성 요소는 서비스에서 가져올 수 있는 객체의 종류, 그리고 포함하는 필드를 나타내는 객체 유형

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

리졸버(Resolver)

요청에 대한 응답을 결정해주는 함수로써 GraphQL의 여러 가지 타입 중 Query, Mutation, Subscription과 같은 타입의 실제 일하는 방식 즉 로직을 작성합니다.
다시 말해 위와 같이 스키마를 정의하면 그 스키마 필드에 사용되는 함수의 실제 행동을 Resolver에서 정의합니다. 또한 이러한 함수들이 모여 있기 때문에 보통 Resolvers라 부릅니다.

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 () => {
      ...
		}
  }
};



GitHub GraphQL API
https://docs.github.com/en/graphql/overview/explorer

profile
메모장/ FE연습장

0개의 댓글