# GraphQL이란?
GraphQL은 페이스북에서 만든 쿼리 언어입니다. 국내에서 GraphQL API를 Open API로 공개한 곳은 드뭅니다.
Graph QL(이하 gql)은 Structed Query Language(이하 sql)와 마찬가지로 쿼리 언어입니다. 하지만 gql과 sql의 언어적 구조 차이는 매우 큽니다. 또한 gql과 sql이 실전에서 쓰이는 방식의 차이도 매우 큽니다. gql과 sql의 언어적 구조 차이가 활용 측면에서의 차이를 가져왔습니다.
REST API의 대체재로 사용될 수 있다.
# 장점 & 특징
sql은 데이터베이스 시스템에 저장된 데이터를 효율적으로 가져오는 것이 목적이고,
gql은 웹 클라이언트가 데이터를 서버로 부터 효율적으로 가져오는 것이 목적입니다.
sql의 문장(statement)은 주로 백앤드 시스템에서 작성하고 호출 하는 반면,
gql의 문장은 주로 클라이언트 시스템에서 작성하고 호출 합니다.
HTTP API 자체가 특정 데이터베이스나 플렛폼에 종속적이지 않은것 처럼 마찬가지로
gql 역시 어떠한 특정 데이터베이스나 플렛폼에 종속적이지 않습니다.
REST API는 URL, METHOD등을 조합하기 때문에 다양한 Endpoint가 존재 합니다.
반면, gql은 단 하나의 Endpoint가 존재
gql API에서는 불러오는 데이터의 종류를 쿼리 조합을 통해서 결정 합니다.
예를 들면, REST API에서는 각 Endpoint마다 데이터베이스 SQL 쿼리가 달라지는 반면,
gql API는 gql 스키마의 타입마다 데이터베이스 SQL 쿼리가 달라집니다.
gql API를 사용하면 여러번 네트워크 호출을 할 필요 없이, 한번의 네트워크 호출로 처리 할 수 있습니다.
기존 rest api의 경우, posts와 comments와 authors를 알고 싶으면, 각 url로 3번의 호출을 해야 했음
graphql의 경우, posts, comments, authors에 대한 쿼리 내용을 하나로 묶어서 요청하면, 한번의 요청으로 전체를 받아올 수 있음
# 쿼리/뮤테이션(query/mutation) 개념
쿼리와 응답 내용 그리고 뮤테이션의 구조는 상당히 직관적 입니다. 요청하는 쿼리문의 구조와 응답 내용의 구조는 거의 일치 합니다.
쿼리는 데이터를 읽는데(R) 사용
뮤테이션은 데이터를 변조(CUD) 하는데 사용한다는 개념
$변수명 형태로, 쿼리에 변수를 사용할 수 있다.
query HeroNameAndFriends($episode: Episode) { hero(episode: $episode) { name friends { name } } }
query getStudentInfomation($studentId: ID){ personalInfo(studentId: $studentId) { name address1 address2 major } classInfo(year: 2018, studentId: $studentId) { classCode className teacher { name major } classRoom { id maintainer { name } } } SATInfo(schoolCode: 0412, studentId: $studentId) { totalScore dueDate } }
오퍼레이션 네임 쿼리는 매우 편리 합니다. 굳이 비유하자면 쿼리용 함수 입니다. 데이터베이스 에서의 프로시져(procedure) 개념과 유사하다고 생각하면 됩니다. 위와 같이 쿼리 한번으로, 여러 Table의 값들을 동시에 받아볼 수 있다.
# 스키마 / 타입 / 필드
type Character { name: String! appearsIn: [Episode!]! }
- 오브젝트 타입 : Character (일반 sql에서는 테이블명과 비슷)
- 필드 : name, appearsIn
- 스칼라 타입 : String, ID, Int 등
- 느낌표(!) : 필수 값을 의미(non-nullable)
- 대괄호([, ]) : 배열을 의미(array)
-> Episode의 경우 관계와 비슷한 개념
# 리졸버
데이터베이스 사용시, 데이터를 가져오기 위해서 sql을 작성 했습니다. 또한, 데이터베이스에는 데이터베이스 어플리케이션을 사용하여 데이터를 가져오는 구체적인 과정이 구현 되어 있습니다. 그러나 gql 에서는 데이터를 가져오는 구체적인 과정을 직접 구현 해야 합니다. gql 쿼리문 파싱은 대부분의 gql 라이브러리에서 처리를 하지만, gql에서 데이터를 가져오는 구체적인 과정은 resolver(이하 리졸버)가 담당하고, 이를 직접 구현 해야 합니다. 프로그래머는 리졸버를 직접 구현해야하는 부담은 있지만, 이를 통해서 데이터 source의 종류에 상관 없이 구현이 가능 합니다. 예를 들어서, 리졸버를 통해 데이터를 데이터베이스에서 가져 올 수 있고, 일반 파일에서 가져 올 수 있고, 심지어 http, SOAP와 같은 네트워크 프로토콜을 활용해서 원격 데이터를 가져올 수 있습니다. 덧붙이면, 이러한 특성을 이용하면 legacy 시스템을 gql 기반으로 바꾸는데 활용 할 수 있습니다.
gql 쿼리에서는 각각의 필드마다 함수가 하나씩 존재 한다고 생각하면 됩니다. 이 함수는 다음 타입을 반환합니다. 이러한 각각의 함수를 리졸버(resolver)라고 합니다. 만약 필드가 스칼라 값(문자열이나 숫자와 같은 primitive 타입)인 경우에는 실행이 종료됩니다. 즉 더 이상의 연쇄적인 리졸버 호출이 일어나지 않습니다. 하지만 필드의 타입이 스칼라 타입이 아닌 우리가 정의한 타입이라면 해당 타입의 리졸버를 호출되게 됩니다.
각각의 리졸버 함수에는 내부적으로 데이터베이스 쿼리가 존재합니다.
type Query { // Query 테이블이라기 보다는, Query 전용으로 타입생성 users: [User] user(id: ID): User limits: [Limit] limit(UserId: ID): Limit paymentsByUser(userId: ID): [Payment] } type User { // 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! }
Query: { // Query 타입에대한 구체적인 resolver 함수 정의 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: { //Payment 타입에 대한 구체적인 resolver 함수 정의 limit: async (payment, args, context, info) => { return await Limit.findOne({ where: { id: payment.LimitId } }) } }
# 리졸버 함수 인자 구성
- 첫번째 인자는 parent로 연쇄적 리졸버 호출에서 부모 리졸버가 리턴한 객체입니다. 이 객체를 활용해서 현재 리졸버가 내보낼 값을 조절 할 수 있습니다.
- 두번째 인자는 args로 쿼리에서 입력으로 넣은 인자입니다.
- 세번째 인자는 context로 모든 리졸버에게 전달이 됩니다. 주로 미들웨어를 통해 입력된 값들이 들어 있습니다. 로그인 정보 혹은 권한과 같이 주요 컨텍스트 관련 정보를 가지고 있습니다.
- 네번째 인자는 info로 스키마 정보와 더불어 현재 쿼리의 특정 필드 정보를 가지고 있습니다. 잘 사용하지 않는 필드입니다.
# 인트로스펙션 (introspection)
기존 rest api처럼 swaggerui와 같인 API 명세서를 작성할 필요가 없이 gql의 인트로스펙션은 서버 자체에서 현재 서버에 정의된 스키마의 실시간 정보를 공유를 할 수 있게 합니다. 이 스키마 정보만 알고 있으면 클라이언트 사이드에서는 따로 연동규격서를 요청 할 필요가 없다. apollo server라는 서버용 gql 라이브러리에 포함 되어있는 웹 IDE 화면에서 확인가능하다.
gql 자체는 쿼리 언어입니다. 이것 만으로는 할 수 있는 것이 없습니다. gql을 실제 구체적으로 활용 할 수 있도록 도와주는 라이브러리들이 몇가지 존재 합니다. gql 자체는 개발 언어와 사용 네트워크에 완전히 독립적
아폴로(Apollo GraphQL)가 주로 사용된다.
# 출처
- https://tech.kakao.com/2019/08/01/graphql-basic/
최근댓글