graphQL은 데이터가 전송되어지는데 사용되는 데이터 질의어(쿼리 언어)다.
이전에는 커뮤니티가 크지 않고 지원도 빈약하여 적용하는데 쉽지 않았었던 반면, 최근에는 이용자 수가 큰만큼 커뮤니티도 크고 수많은 프레임워크의 공식문서에서 확인할 수 있을만큼 지원이 잘 되고 있다.
REST API의 단점을 보완하여 현업에서도 자주 병용되어지는 graphQL, 전반적인 간단한 개념을 오늘 알아보았다.
Why graphQL?
graphQL의 장점
- 필요한 정보들만 선택하여 받아올 수 있음
- Overfetching 문제 해결
- 데이터 전송량 감소
- 여러 계층의 정보들을 한 번에 받아올 수 있음
- Underfetching 문제 해결
- 요청 횟수 감소
- 하나의 endpoint에서 모든 요청을 처리
- 하나의 URI에서 POST로 모든 요청 가능
REST API와 graphQL 간단 비교
REST API graphQL
조회 | GET | query |
생성 | POST | mutation |
graphQL 서버 만들어보기
Apollo 서버 구축하기
const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')
const typeDefs = gql`
type Query {
teams: [Team]
}
type Team {
id: Int
manager: String
office: String
extension_number: String
mascot: String
cleaning_duty: String
project: String
}
`
const resolvers = {
Query: {
teams: () => database.teams
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
서버 세팅 예제
ApolloServer
- typeDef와 resolver를 인자로 받아 서버 생성
typeDef
- graphQL 명세에서 사용될 데이터, 요청의 타입 지정
- gql(template literal tag)로 생성됨
resolver
- 서비스의 액션들을 함수로 지정
- 요청에 따라 데이터를 반환, 입력, 수정, 삭제
Query 구현하기
Query 루트 타입
type Query {
teams: [Team]
}
- 자료 요청에 사용될 쿼리들을 정의하고 쿼리문마다의 반환될 데이터 타입 지정
Type
type Team {
id: Int
manager: String
office: String
extension_number: String
mascot: String
cleaning_duty: String
project: String
}
- 반환될 데이터의 형태를 지정하고, 자료형을 가진 필드들로 구성됨
Resolver
const resolvers = {
Query: {
teams: () => database.teams
}
}
- Query란 object의 항목들로 데이터를 반환하는 함수 선언
Mutation 구현하기
- 반드시 query를 조회하는데 쓰고, mutation을 생성 또는 수정에 사용할 필요는 없지만, REST API에서 GET, POST가 구분되어 사용되는 것처럼 일종의 컨벤션이라고 할 수 있음
데이터 삭제
예제) String 인자 id를 받는 deleteEquipment: 삭제된 Equipment를 반환
type Mutation {
deleteEquipment(id: String): Equipment
}
삭제 resolver
Mutation: {
deleteEquipment: (parent, args, context, info) => {
const deleted = database.equipments
.filter((equipment) => {
return equipment.id === args.id
})[0]
database.equipments = database.equipments
.filter((equipment) => {
return equipment.id !== args.id
})
return deleted
}
}
데이터 추가
Mutation
type Mutation {
insertEquipment(
id: String,
used_by: String,
count: Int,
new_or_used: String
): Equipment
...
}
추가 resolver
Mutation: {
insertEquipment: (parent, args, context, info) => {
database.equipments.push(args)
return args
},
//...
}
데이터 수정
Mutation
type Mutation {
editEquipment(
id: String,
used_by: String,
count: Int,
new_or_used: String
): Equipment
...
}
수정 resolver
Mutation: {
// ...
editEquipment: (parent, args, context, info) => {
return database.equipments.filter((equipment) => {
return equipment.id === args.id
}).map((equipment) => {
Object.assign(equipment, args)
return equipment
})[0]
},
// ...
}
graphQL 서버 깊이 파보기
서버 구성요소 모듈화
typeDef, resolver들을 모듈화하여 효율적으로 관리 가능
GraphQL의 기본 타입들
- graphQL 기본 자료형
타입 설명
ID | 기본적으로는 String이나, 고유 식별자 역할임을 나타냄 |
String | UTF-8 문자열 |
Int | 부호가 있는 32비트 정수 |
Float | 부호가 있는 부동소수점 값 |
Boolean | 참/거짓 |
!: Non Null
열거 타입(enum)
리스트 타입
- 특정 타입의 배열을 반환
유니언과 인터페이스
유니언
두 가지 필드를 동시에 반환하게 할 수 있다.
반환 값 중 __typename 의 값을 통해 어떤 필드 값인지 알 수 있다.
인터페이스
- 지정된 타입에서 특정 필드를 구현할 것을 약속하는 추상형식의 타입
- 추상 타입 - 다른 타입에 implement 되기 위한 타입
인자와 인풋 타입
- typeDef에서 인자를 명시하고, 받아와서 새로운 메서드에서 사용할 수 있다.
- 페이지네이션, 필터링하는데 사용될 수 있다.
💡 참고: enum 값은 따옴표가 필요 없다
query를 통해 반환값을 얻을 때, 별칭을 직접 정할 수 있다.
예제)
query {
badGuys: peopleFiltered(sex: male, blood_type: B) {
first_name
last_name
sex
blood_type
}
newYorkers: peopleFiltered(from: "New York") {
first_name
last_name
from
}
}
'정보' 카테고리의 다른 글
[macOS] 도메인 접근 허용하기 (0) | 2023.05.05 |
---|---|
[Prisma] Prisma 알아보기 (4) | 2023.04.23 |
[NestJS] Failed to execute command: npm install --silent 에러 (0) | 2023.02.23 |
[Docker] 도커 알아보기 (1) | 2022.11.21 |
can't open file '<경로>' : [Errno 2] No such file or directory // 경로에 문제가 없을 경우 (0) | 2022.09.22 |