GraphQL은 (명세, 형식) 쿼리 언어로 구현할 솔루션이 필요하다.
이를 위한 라이브러리로는 GraphQL.js, GraphQL Yoga, AWS Amplift, Apollo GraphQL
const { ApolloServer, gql } = require('apollo-server')
const database = require('./database')
/**
* typeDef
* GraphQL 명세에서 사용될 데이터, 요청 타입 지정
* gql (template literal tag) 로 생성됨
*/
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
}
/**
* resolver
* 서비스의 액션들을 함수로 지정
* 요청에 따라 데이터를 반환, 입력, 수정, 삭제
*/
const resolvers = {
Query: {
teams: () => database.teams
.map((team) => {
team.supplies = database.supplies
.filter((supply) => {
return supply.team === team.id
})
return team
})
}
// ApolloServer : typeDef와 resolver를 인자로 받아 서버 생성
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
오브젝트 타입과 필드
스칼라 타입
!Non Null
Null을 반환할 수 없음.
열거 타입
미리 지정된 값들중에서만 반환.(ex. enum)
리스트 타입
특정 타입의 배열을 반환.
객체 타입
사용자에 의해 정의된 타입들
Union
타입 여럿을 한 배열에 반환하고자 할 때 사용
Interface
유사한 객체 타입을 만들기 위한 공통 필드 타입
추상 타입 - 다른 타입에 implements 되기 위한 타입
인자와 인풋 타입
1. 필터
[Query type]
type Query {
...
peopleFiltered(
team: Int,
sex: Sex,
blood_type: BloodType,
from: String
): [People]
...
}
=======================================================================
[DB work]
getPeople: (args) => dataFiltered('people', args)
.map((person) => {
person.tools = [
...dbWorks.getEquipments({used_by: person.role}),
...dbWorks.getSoftwares({used_by: person.role})
]
person.givens = [
...dbWorks.getEquipments({used_by: person.role}),
...dbWorks.getSupplies({team: person.team})
]
return person
}),
======================================================================
[request]
query {
peopleFiltered (
team: 1
blood_type: B
from: "Texas"
) {
id
first_name
last_name
sex
blood_type
serve_years
role
team
from
}
}
[Query type]
type Query {
...
peoplePaginated(
page: Int!,
per_page: Int!
): [People]
...
}
======================================================================
[DB work]
if (args.page && args.per_page) {
result = result.slice(
(args.page - 1) * args.per_page,
args.page * args.per_page)
}
======================================================================
[request]
query {
peoplePaginated(page: 1, per_page: 7) {
id
first_name
last_name
sex
blood_type
serve_years
role
team
from
}
}
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
}
}
[Query type]
const typeDefs = gql`
....
input PostPersonInput {
first_name: String!
last_name: String!
sex: Sex!
blood_type: BloodType!
serve_years: Int!
role: Role!
team: ID!
from: String!
}
`
const resolvers = {
// ...
Mutation: {
postPerson: (parent, args) => dbWorks.postPerson(args),
}
}
======================================================================
[request]
mutation {
postPerson(input: {
first_name: "Hanna"
last_name: "Kim"
sex: female
blood_type: O
serve_years: 3
role: developer
team: 1
from: "Pusan"
}) {
id
first_name
last_name
sex
blood_type
role
team
from
}
}
리팩토링을 위한 정리
RestAPI에 비해 Back과 Front의 협업이 한층 수월해 질 것으로 보인다. 기존 response를 Back에서 전적으로 담당하던 것에 대해 그 영역이 Front로 넘어간 것으로 overfetching이나 underfetching을 해소하기 위한 중복적인 개발도 감소 할 것으로 예상된다.