graphQL - 형식일 뿐
GraphQL을 구현할 솔루션 - BE에서 정보를 제공 및 처리하고, FE에서 요청 전송 - GraphQL.js, GraphQL Yoga...
→ Apollo : BE, FE 를 모두 제공한다. 간편하고 쉬운 설정
npm i - apollo-server
const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')
// 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
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
ApolloServer
: typeDefs
와 resolvers
를 받아 server를 return 한다.
typeDefs
: graphQL 명세에서 사용될 데이터, 요청의 타입을 지정한다. gql로 생성된다
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
}
`
Query 명령문마다 사용될 쿼리들을 정의하고, 명령문마다 반환될 데이터 형태를 지정한다. 위에서는 teams는 Team 객체의 배열로 return 된다는 것을 명시
resolvers
: 서비스의 액션(데이터를 반환, 입력, 수정, 삭제)들을 함수로 지정한다. const resolvers = {
Query: {
teams: () => database.teams
}
}
Query
라는, 데이터를 반환하는 함수를 새롭게 선언해준 것.
const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')
// graphQL 명세에서 사용될 데이터, 요청의 타입을 지정하는 것
// gql(template literal tag) 로 생성된다.
const typeDefs = gql`
type Query {
teams: [Team]
equipments: [Equipment]
supplies: [Supply]
}
type Team {
id: Int
manager: String
office: String
extension_number: String
mascot: String
cleaning_duty: String
project: String
}
type Equipment {
id: String
used_by: String
count: Int
new_or_used: String
}
type Supply {
id: String
team: Int
}
`
// resolver : 서비스의 액션들을 함수로 지정(데이터를 반환, 입력, 수정, 삭제)
const resolvers = {
Query: {
teams: () => database.teams,
equipments : () => database.equipments,
supplies : () => database.supplies,
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')
const typeDefs = gql`
type Query {
...
team(id: Int): Team
}
...
`
// resolver : 서비스의 액션들을 함수로 지정(데이터를 반환, 입력, 수정, 삭제)
const resolvers = {
Query: {
teams: () => database.teams,
team: (parent, args, context, info) => database.teams.
filter(item => {
return item.id === args.id;
})[0],
...
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
query {
team(id:1) {
id,
manager,
office
}
}
Team 에 supply 연결
const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')
const typeDefs = gql`
type Query {
teams: [Team]
equipments: [Equipment]
supplies: [Supply]
team(id: Int): Team
}
type Team {
id: Int
manager: String
office: String
extension_number: String
mascot: String
cleaning_duty: String
project: String,
supplies: [Supply]
}
...
`
// resolver : 서비스의 액션들을 함수로 지정(데이터를 반환, 입력, 수정, 삭제)
const resolvers = {
Query: {
teams: () => database.teams
.map((team) => {
team.supplies = database.supplies
.filter((supply) => {
return supply.team === team.id
})
return team
})
,
...
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
Team
의 typeDefs
에 supplies
를 추가하고, teams()
함수를 변경해줬다.
query {
teams {
id
manager
supplies {
id
team
}
}
}
mutation
? 데이터를 변경하는 것이다.
정보를 받아올 때는 query, 수정, 추가 시에는 mutation을 이용한다.
typeDefs
에 type Mutation 추가
type Mutation {
deleteEquipment(id: String): Equipment
}
resolvers
에 deleteEquipment
추가
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
}
const typeDefs = gql`
type Mutation {
insertEquipment(
id: String,
used_by: String,
count: Int,
new_or_used: String
): Equipment
...
}
...
`
역시 resolver
에 추가한 후
mutation {
insertEquipment (
id: "laptop",
used_by: "developer",
count: 17,
new_or_used: "new"
) {
id
used_by
count
new_or_used
}
}
params을 생략하면 null로 들어간다.
typeDefs
와 resolvers
는 단순한 Object 뿐만 아니라 Array 를 받을 수도 있다.
const { ApolloServer } = require('apollo-server')
const queries = require('./typedefs-resolvers/_queries')
const mutations = require('./typedefs-resolvers/_mutations')
const equipments = require('./typedefs-resolvers/equipments')
const typeDefs = [
queries,
mutations,
equipments.typeDefs,
]
const resolvers = [
equipments.resolvers
]
const server = new ApolloServer({typeDefs, resolvers})
server.listen().then(({url}) => {
console.log(`🚀 Server ready at ${url}`)
})
root query들은 ./typedefs-resolvers/_queries
에, root mutation들은 ./typedefs-resolvers/_mutations
에 위치
const { gql } = require('apollo-server')
const typeDefs = gql`
type Query {
equipments: [Equipment]
}
`
module.exports = typeDefs
const { gql } = require('apollo-server')
const typeDefs = gql`
type Mutation {
deleteEquipment(id: String): Equipment
}
`
module.exports = typeDefs
typedefs-resolvers/equipments.js
Equipment
에 대한 typeDefs와 resolver 함수들을 정의한다.
const { gql } = require('apollo-server')
const dbWorks = require('../dbWorks')
const typeDefs = gql`
type Equipment {
id: String
used_by: String
count: Int
new_or_used: String
}
`
const resolvers = {
Query: {
equipments: (parent, args) => dbWorks.getEquipments(args),
},
Mutation: {
deleteEquipment: (parent, args) => dbWorks.deleteItem('equipments', args),
}
}
module.exports = {
typeDefs: typeDefs,
resolvers: resolvers
}
type EquipmentAdv {
id: ID!
used_by: String!
count: Int!
use_rate: Float
is_new: Boolean!
}
true, false 값만 반환하는 Boolean 처럼 정해진 값들만 반환하는 것
db에 엉뚱한 값이 들어가는 것을 막을 수 있다
const { gql } = require('apollo-server')
const typeDefs = gql`
enum Role {
developer
designer
planner
}
enum NewOrUsed {
new
used
}
`
module.exports = typeDefs
const enums = require('./typedefs-resolvers/_enums')
const typeDefs = [
enums,
...
]
...
Equipment와 Supply를 함께 반환하기
givens.js
const { gql } = require('apollo-server')
const dbWorks = require('../dbWorks.js')
const typeDefs = gql`
union Given = Equipment | Supply
`
const resolvers = {
Query: {
givens: (parent, args) => {
return [
...dbWorks.getEquipments(args),
...dbWorks.getSupplies(args)
]
}
},
Given: {
__resolveType(given, context, info) {
if (given.used_by) {
return 'Equipment'
}
if (given.team) {
return 'Supply'
}
return null
}
}
}
module.exports = {
typeDefs: typeDefs,
resolvers: resolvers
}
__resolveType
: __typename을 지정해준다. query {
givens {
__typename
... on Equipment {
id
used_by
count
new_or_used
}
... on Supply {
id
team
}
}
}
__typename
: Given
함수의 __resolveType
에서 리턴해준 것
... on Equipment
: __typename
이 'Equipment' 일때 반환할 field
const { gql } = require('apollo-server')
const typeDefs = gql`
interface Tool {
id: ID!
used_by: Role!
}
`
const resolvers = {
Tool: {
__resolveType(tool, context, info) {
if (tool.developed_by) {
return 'Software'
}
if (tool.new_or_used) {
return 'Equipment'
}
return null
}
}
}
module.exports = {
typeDefs: typeDefs,
resolvers: resolvers
}
type Equipment implements Tool {
id: ID!
used_by: Role!
count: Int
new_or_used: NewOrUsed!
}
type Equipment implements Tool {
id: ID!
used_by: Role!
count: Int
new_or_used: NewOrUsed!
}
type Query {
...
peopleFiltered(
team: Int,
sex: Sex,
blood_type: BloodType,
from: String
): [People]
...
}
query {
peopleFiltered (
team: 1
blood_type: B
sex:female
) {
id
first_name
last_name
sex
blood_type
serve_years
role
team
from
}
}
enum 은 ""를 쓰지 않는다!
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
}
}
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),
}
}
type Mutation {
postPerson(input: PostPersonInput): People!
...
}
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
}
}