10. GraphQL Schema
type User {
name: String
friendsCount: Int
friends(first: Int!): [User]
}
Default Scalar Types in GraphQL Schema
Int Float String Boolean
User-made Object Type
14. {
me {
name
friends {
name
}
}
}
Basic Query
{
"errors": [
{
"message": "must provide first"
}
]
}
type User {
name: String
friendsCount: Int
friends(first: Int!): [User]
}
15. {
me {
name
friends(first: 2) {
name
}
}
}
Basic Query
type User {
name: String
friendsCount: Int
friends(first: Int!): [User]
}
16. {
me {
name
friends(first: 2) {
name
}
}
}
Basic Query
type User {
name: String
friendsCount: Int
friends(first: Int!): [User]
}
{
“data”: {
“me”: {
“name”: “Minhwan Cho”,
“friends”: [
{ “name”: “Naru Han” },
{ “name”: “Woori Chae” }
]
}
}
}
17. {
me {
friends(first: 2) {
name
friendsCount
}
}
}
Basic Query
type User {
name: String
friendsCount: Int
friends(first: Int!): [User]
}
18. {
me {
friends(first: 2) {
name
friendsCount
}
}
}
Basic Query
type User {
name: String
friendsCount: Int
friends(first: Int!): [User]
} {
“data”: {
“me”: {
“friends”: [
{
“name”: “Naru Han”,
“friendsCount”: 204
},
{
“name”: “Woori Chae”,
“friendsCount”: 53
}
]
}
}
}
41. REST API
GET : /starships?pilotInfo=true서버 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
42. REST API
GET : /starships?pilotInfo=true서버 개발자
UI 코드 수정…
클라 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
43. REST API
GET : /starships?pilotInfo=true서버 개발자
UI 코드 수정…
클라 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
‘어… 잠깐 웹에서는 고향 행성 이름까지 필요하다고 해서 구현해놨는데 모바일도?’서버 개발자
(가서 물어본다)
44. REST API
GET : /starships?pilotInfo=true서버 개발자
UI 코드 수정…
클라 개발자
“아니요~ 화면 작아서 고향 행성 이름은 표시 안하기로 했어요”클라 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
‘어… 잠깐 웹에서는 고향 행성 이름까지 필요하다고 해서 구현해놨는데 모바일도?’서버 개발자
(가서 물어본다)
45. REST API
GET : /starships?pilotInfo=true서버 개발자
UI 코드 수정…
클라 개발자
“아니요~ 화면 작아서 고향 행성 이름은 표시 안하기로 했어요”클라 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
‘어… 잠깐 웹에서는 고향 행성 이름까지 필요하다고 해서 구현해놨는데 모바일도?’서버 개발자
(가서 물어본다)
GET : /starships?
pilotInfo=true&homeworld=no
서버 개발자
46. REST API
GET : /starships?pilotInfo=true서버 개발자
UI 코드 수정…
클라 개발자
“아니요~ 화면 작아서 고향 행성 이름은 표시 안하기로 했어요”클라 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
‘어… 잠깐 웹에서는 고향 행성 이름까지 필요하다고 해서 구현해놨는데 모바일도?’서버 개발자
(가서 물어본다)
GET : /starships?
pilotInfo=true&homeworld=no
서버 개발자 UI 코드 수정…
클라 개발자
47. REST API
GET : /starships?pilotInfo=true서버 개발자
UI 코드 수정…
클라 개발자
“아니요~ 화면 작아서 고향 행성 이름은 표시 안하기로 했어요”클라 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
‘어… 잠깐 웹에서는 고향 행성 이름까지 필요하다고 해서 구현해놨는데 모바일도?’서버 개발자
(가서 물어본다)
GET : /starships?
pilotInfo=true&homeworld=no
서버 개발자
서버 개발자 (새로운 API parameter 문서 업데이트)
UI 코드 수정…
클라 개발자
48. REST API
GET : /starships?pilotInfo=true서버 개발자
UI 코드 수정…
클라 개발자
“아니요~ 화면 작아서 고향 행성 이름은 표시 안하기로 했어요”클라 개발자
“우주선 API에서 파일럿 정보도 주실 수 있나요?”클라 개발자
‘어… 잠깐 웹에서는 고향 행성 이름까지 필요하다고 해서 구현해놨는데 모바일도?’서버 개발자
(가서 물어본다)
서버 API 코드를 작성하는데 클라이언트에서 요청한 GET 요청 한 문장으로는
어떠한 것도 결정할 수 없다.
input -> output 이 아니라 해당 URL을 때리면 사전에 개발자 끼리 약속한 결과를 주는 것 ->
API 상세 의존성이 개발자 끼리의 대화, 문서에 있음
GET : /starships?
pilotInfo=true&homeworld=no
서버 개발자
서버 개발자 (새로운 API parameter 문서 업데이트)
UI 코드 수정…
클라 개발자
50. GraphQL API
“API에서 파일럿 정보가 필요하네?”클라 개발자
{
starship(id: $id) {
pilot(first: 3) {
name
profileImage
}
}
}
클라 개발자
51. GraphQL API
“API에서 파일럿 정보가 필요하네?”클라 개발자
{
starship(id: $id) {
pilot(first: 3) {
name
profileImage
}
}
}
클라 개발자
UI 코드 수정클라 개발자
52. GraphQL API
“API에서 파일럿 정보가 필요하네?”클라 개발자
{
starship(id: $id) {
pilot(first: 3) {
name
profileImage
}
}
}
클라 개발자
UI 코드 수정클라 개발자
우주선 파일럿은 몇명을 가져와야하는지,
고향 행성정보는 필요한지 아닌지 그 누구한테도
일일히 말할 필요 없다.
UI 디자이너와 클라이언트 개발자만 이야기 끝나면 된다
53. GraphQL API
“API에서 파일럿 정보가 필요하네?”클라 개발자
{
starship(id: $id) {
pilot(first: 3) {
name
profileImage
}
}
}
클라 개발자
UI 코드 수정클라 개발자
서버 코드는 모델의 Schema만 작성하면 된다
우주선 파일럿은 몇명을 가져와야하는지,
고향 행성정보는 필요한지 아닌지 그 누구한테도
일일히 말할 필요 없다.
UI 디자이너와 클라이언트 개발자만 이야기 끝나면 된다
54. GraphQL API
“API에서 파일럿 정보가 필요하네?”클라 개발자
서버에서는 리퀘스트로 오는 쿼리문만 있으면 된다.
GET url parameter를 보고 무엇을 줘야할지 추측할 필요가 없다
외부의 스펙이나 약속이나 문서에 의존적이지 않은 코드를 작성할 수 있다.
클라이언트에서도 수시로 업데이트되는 UI를 구현하는데 허들이 낮아진다.
{
starship(id: $id) {
pilot(first: 3) {
name
profileImage
}
}
}
클라 개발자
UI 코드 수정클라 개발자
서버 코드는 모델의 Schema만 작성하면 된다
우주선 파일럿은 몇명을 가져와야하는지,
고향 행성정보는 필요한지 아닌지 그 누구한테도
일일히 말할 필요 없다.
UI 디자이너와 클라이언트 개발자만 이야기 끝나면 된다
55. API 네트워크 요청에서 “N + 1 Problem” 을 방지
GraphQL 장점!
{
users(first: 20) {
id
name
age
…
}
}
GET : /users/Syojd1Apx
GET : /users/rJeqtkA6g
GET : /users/HJoFt1Rpl
..
.
GET : /users/B1PFYyAax
GET : /users?limit=20
GET : /users/CyljpJxCT
11
N
56. API 네트워크 요청에서 “N + 1 Problem” 을 방지
GraphQL 장점!
{
users(first: 20) {
id
name
age
…
}
}
GET : /users/Syojd1Apx
GET : /users/rJeqtkA6g
GET : /users/HJoFt1Rpl
..
.
GET : /users/B1PFYyAax
GET : /users?limit=20
GET : /users/CyljpJxCT
11
N
57. API 네트워크 요청에서 “N + 1 Problem” 을 방지
GraphQL 장점!
{
users(first: 20) {
id
name
age
…
}
}
GET : /users/Syojd1Apx
GET : /users/rJeqtkA6g
GET : /users/HJoFt1Rpl
..
.
GET : /users/B1PFYyAax
GET : /users?limit=20
진짜?
GET : /users/CyljpJxCT
11
N
59. 데이타베이스 요청에서 “N + 1 Problem” 발생
GraphQL 주의할 점!
..
.
SELECT * from ‘users’;
{
users(first: 20) {
id
name
age
…
}
SELECT * from ‘users’ WHERE id = ‘Syojd1Apx’;
SELECT * from ‘users’ WHERE id = ‘rJeqtkA6g’;
SELECT * from ‘users’ WHERE id = ‘HJoFt1Rpl’;
SELECT * from ‘users’ WHERE id = ‘CyljpJxCT’;
SELECT * from ‘users’ WHERE id = ‘B1PFYyAax’;
1
N
60. 지수적으로 차수가 심각하게 증가한다
{
me {
name
age
}
}
GraphQL 더 주의할 점!
SELECT name, age FROM ‘users’ WHERE id=$token.user.id;
Database SQL Call Count : 1
1
61. 지수적으로 차수가 심각하게 증가한다
{
me {
name
age
friends(first: N) {
name
}
}
}
GraphQL 더 주의할 점!
SELECT name, age FROM ‘users’ WHERE id=$token.user.id;
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
..
.
SELECT name FROM ‘users’ WHERE id=…;
N
1
Database SQL Call Count : 1 + N
62. {
me {
name
age
friends(first: N) {
name
friends(first: N) {
name
}
}
}
}
GraphQL 더 주의할 점!
SELECT name, age FROM ‘users’ WHERE id=$token.user.id;
Database SQL Call Count : 1 + N + N
SELECT name FROM ‘users’ WHERE id=…;
2
1
N
..
.
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
N
SELECT name FROM ‘users’ WHERE id=…;
..
.
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
N
..
.
지수적으로 차수가 심각하게 증가한다
63. 실제 사례
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
/cells 페이지에서는 모든 셀의 간략한 정보가 필요해!
어떤일을 하는지 필요할 것 같아.
그런데 각 일마다 어떤 사람이 참여하는지 알면 좋을것 같애
근데 사람을 표시하는 프로필사진을 hover하면
그 사람이 어떤일 하는지도 알 수 있으니 좋을것 같군!
64. 실제 사례
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
/cells 페이지에서는 모든 셀의 간략한 정보가 필요해!
어떤일을 하는지 필요할 것 같아.
그런데 각 일마다 어떤 사람이 참여하는지 알면 좋을것 같애
근데 사람을 표시하는 프로필사진을 hover하면
그 사람이 어떤일 하는지도 알 수 있으니 좋을것 같군!
65. 실제 사례
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
/cells 페이지에서는 모든 셀의 간략한 정보가 필요해!
어떤일을 하는지 필요할 것 같아.
그런데 각 일마다 어떤 사람이 참여하는지 알면 좋을것 같애
근데 사람을 표시하는 프로필사진을 hover하면
그 사람이 어떤일 하는지도 알 수 있으니 좋을것 같군!
20 + 20x5 + 20x5x10 + 20x5x10x5 = 6120
66. 실제 사례
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
/cells 페이지에서는 모든 셀의 간략한 정보가 필요해!
어떤일을 하는지 필요할 것 같아.
그런데 각 일마다 어떤 사람이 참여하는지 알면 좋을것 같애
근데 사람을 표시하는 프로필사진을 hover하면
그 사람이 어떤일 하는지도 알 수 있으니 좋을것 같군!
20 + 20x5 + 20x5x10 + 20x5x10x5 = 6120
서비스 런칭 1시간 30분만에 서버 다운
67. 시도했던 퍼포먼스 최적화 방법
• GraphQL query에서 Leaf 자르기
• Batch call로 한번에 resolve 하기
68. Leaf 자르기
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
사람 프로필에 hover하면 하고 있는 일 목록 나오는 것
hover할때 리퀘스트를 따로 보내서 lazy loading 한다
20 + 20x5 + 20x5x10 + 20x5x10x5 = 6120
69. Leaf 자르기
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
사람 프로필에 hover하면 하고 있는 일 목록 나오는 것
hover할때 리퀘스트를 따로 보내서 lazy loading 한다
20 + 20x5 + 20x5x10 + 20x5x10x5 = 6120
70. Leaf 자르기
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
사람 프로필에 hover하면 하고 있는 일 목록 나오는 것
hover할때 리퀘스트를 따로 보내서 lazy loading 한다
20 + 20x5 + 20x5x10 + 20x5x10x5 = 6120
71. Leaf 자르기
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
사람 프로필에 hover하면 하고 있는 일 목록 나오는 것
hover할때 리퀘스트를 따로 보내서 lazy loading 한다
20 + 20x5 + 20x5x10 + 20x5x10x5 =
72. Leaf 자르기
{
cells {
id
name
.. .
tasks {
id
name
endDate
.. .
members {
name
tasks {
name
endDate
}
}
}
}
}
20
5
10
5
사람 프로필에 hover하면 하고 있는 일 목록 나오는 것
hover할때 리퀘스트를 따로 보내서 lazy loading 한다
20 + 20x5 + 20x5x10 + 20x5x10x5 = 1120
73. SELECT name FROM ‘users’ WHERE id=$token.user.id;
1 + N + N
2
1
N
..
.
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
N
SELECT name FROM ‘users’ WHERE id=…;
..
.
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
SELECT name FROM ‘users’ WHERE id=…;
N
..
.
Batch Call with SQL “IN”
Database SQL Call Count :
{
me {
name
friends(first: N) {
name
friends(first: N) {
name
}
}
}
}
1
N
N
2
SELECT name FROM ‘users’ WHERE id=…;
74. 1
Batch Call with SQL “IN”
Database SQL Call Count :
SELECT name FROM ‘users’ WHERE id IN (
'r1R9Cx06x',
'HklRqCgCal',
‘BJ-AqAeCal’,
…
'C1fRqAeApx',
'S1XC9AeCpg'
);
1
N
1 + 11 + 1
1 SELECT name FROM ‘users’ WHERE id IN (
);
N x N
SELECT name FROM ‘users’ WHERE id=$token.user.id;
{
me {
name
friends(first: N) {
name
friends(first: N) {
name
}
}
}
}
1
1
1
75. 1 + N + N
2
1 + 11 + 1
SQL query 6120개 SQL query 3개
GraphQL 주의할 점!
Batch Call을 하여서 데이터베이스 최적화를 하자!
중간 중간 Relation Table 쿼리는 생략
76. 마무리
• GraphQL API를 한번 만들어 놓으니 클라이언트 개
발할때 훨씬 수월하고 개발 만족도가 높았다.
• 일하는 방식이 많이 개선됨
• 다음번 프로젝트에서도 데이터간 관계가 일정 수준
이상으로 얽혀있으면 GraphQL 적극 도입할 생각
• 팀의 다른 개발자분들께서도 도입 효과를 기대하시
고 공감하신다면 도입을 조심스레 추천