본문 바로가기

언어

GraphQL 개념이해

#GraphQL 배경

Facebook에서 만든 Graph Query Language로 어플리케이션 레이어 쿼리 언어이다. 즉 API를 위한 쿼리언어이며 타입 시스템을 사용하여 쿼리를 실행하는 서버사이드 런타임이며 특정한 데이터베이스나 스토리지에 귀속되어 있지 않으며 기존 코드와 데이터에 의해 대체되는 언어이다.

 

#GraphQL 개념

Graph QL(gql)은 sql의 언어적 구조차이는 매우크다. sql의 경우 데이터베이스 시스템에 저장된 데이터를 효율적으로 가져오는 것이 목적이라면 gql은 웹 클라이언트가 데이터를 서버로부터 효율적으로 가져오는 목적을 가지고 있다. 또한 sql의 문장은 주로 백앤드 시스템에서 작성하는 반면 gql의 문장은 주로 클라이언트 시스테에서 작성하고 호출하게 된다.

 

#GraphQL 요청방식

서버사이드 gql 어플리케이션은 gql로 작성된 쿼리를 입력으로 받아 처리결과를 다시 클라이언트로 리턴해준다.

일반적으로 gql은 네트워크 레이어 L7(HTTP) POST 메소드와 웹소켓 프로토콜을 활용하며 필요에 따라 L4 TCP/UDP를 활용할 수 있다.

 

#GraphQL 구조

쿼리/뮤테이션(query/mutation)의 경우 내부적인 구조는 별 차이가 없으나 명시된 규약으로는 쿼리는 데이터를 읽기위한 용도이며 뮤테이션은 데이터를 변조(CUD)하는데 사용한다.

 

ex) 쿼리문 요청 및 응답

#쿼리문 요청 값
{
	hero {
    	name
   }
}

#쿼리문 응답 값

{
	"data": {
    	"hero" : {
        	"name" : "user"
        }
    }
}

 

ex) 뮤테이션 요청 및 응답

# 뮤테이션 요청 값
{
  human(id: "1000") {
    name
    height
  }
}

# 뮤테이션 응답 값
query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}

 

#스키마/타입(schema/type)

데이터베이스 스키마(schema)를 작성할 때의 경험을 SQL 쿼리 작성으로 비유한다면, gql 스키마를 작성할 때의 경험은 C, C++의 헤더파일 작성에 비유된다.

 

ex) 오브젝트 타입 예시

type Character {
  name: String!
  appearsIn: [Episode!]!
}
  • 오브젝트 타입 : Character
  • 필드 : name, appearsIn
  • 스칼라 타입 : String, ID, Int 등
  • 느낌표(!) : 필수 값을 의미(non-nullable)
  • 대괄호([, ]) : 배열을 의미(array)

#리졸버(resolver)

gql 에서는 데이터를 가져오는 구체적인 과정을 직접 구현 해야 합니다. gql 쿼리문 파싱은 대부분의 gql 라이브러리에서 처리를 하지만, gql에서 데이터를 가져오는 구체적인 과정은 resolver(이하 리졸버)가 담당하고, 이를 직접 구현 해야한다.


ex) 리졸버 구현 예시

type Query {
  users: [User]
  user(id: ID): User
  limits: [Limit]
  limit(UserId: ID): Limit
  paymentsByUser(userId: ID): [Payment]
}

type User {
	id: ID!
	name: String!
	sex: SEX!
	birthDay: String!
	phoneNumber: String!
}

type Limit {
	id: ID!
	UserId: ID
	max: Int!
	amount: Int
	user: User
}

type Payment {
	id: ID!
	limit: Limit!
	user: User!
	pg: PaymentGateway!
	productName: String!
	amount: Int!
	ref: String
	createdAt: String!
	updatedAt: String!
}

 

User와 Limit은 1:1 관계이며 User와 Payment는 1:n 관계이다.

{
  paymentsByUser(userId: 10) {
    id
    amount
  }
}
{
  paymentsByUser(userId: 10) {
    id
    amount
    user {
      name
      phoneNumber
    }
  }
}

 

참고) 리졸버 함수의 경우는 4가지 인자 값을 받을 수 있다.

 Query: {
    paymentsByUser: async (parent, { userId }, context, info) => {
        const limit = await Limit.findOne({ where: { UserId: userId } })
        const payments = await Payment.findAll({ where: { LimitId: limit.id } })
        return payments        
    },  
  },
  Payment: {
    limit: async (payment, args, context, info) => {
      return await Limit.findOne({ where: { id: payment.LimitId } })
    }
  }
  • 첫번째 인자는 parent로 연쇄적 리졸버 호출에서 부모 리졸버가 리턴한 객체
  • 두번째 인자는 args로 쿼리에서 입력으로 넣은 인자
  • 세번째 인자는 context로 모든 리졸버에게 전달
  • 네번째 인자는 info로 스키마 정보와 현재 쿼리의 특정 필드 정보

'언어' 카테고리의 다른 글

[Python] OpenCV 모듈 활용 - 2  (0) 2021.06.09
[Python] OpenCV 모듈 활용 - 1  (0) 2021.06.09
[Python] 큐싱(Qshing)이란?  (0) 2021.06.08