Graphql
그래프큐엘의 장점
- HTTP 리퀘스트가 줄어든다
- 서버로부터 많은 양의 데이터를 받은 후, 이를 파싱해야하는 작업이 줄어든다.
- 파싱하고 이를 로컬 스토어에 저장하는 수고를 덜 수 있다.
위의 과정이 줄어드는 이유? 선언적으로 데이터에 대한 요구사항을 명시하면, 해당 데이터만을 받아 올 수 있다.
GraphQL 은 하나의 end point 를 통해서 동작한다.
하나의 End point 에서 특정 구조의 데이터를 보내주는 rest api와 다르게, graphql의 경우에는 반환되는 데이터가 고정되어 있지 않다.
Query / Mutation / subscription
Schema Query / Mutation / Subscription 은 root type의 일종이다.
client에서 query를 날릴때 type Query
는 일종의 진입점(entry point) 가 된다.
allPerson
의 경우에는 API의 root field가 된다.
type Query{
allPerson: [Person]!
}
아키텍처
- DB와 연결된 GraphQL server
- legacy system이나 써드 파티와 연결된 thin layer 역할을 하는 GraphQL server
- 위 두개가 믹스된 형태
DB와 연결된 Graphql server
레거시가 없이 새로 만들어지는 프로젝트에서 사용되는 아키텍처.
Graphql 서버가 데이터베이스에 접근해서 쿼리를 resolving(해결) 해버리고, 쿼리에 대한 응답을 해준다.
Resolver
클라이언트에서 쿼리를 날리는 경우에, 해당 쿼리에서 요구하는 데이터 필드에 해당하는 모든 Resolver 함수가 호출된다. 그리고 Resolver 함수에 의해서 처리되는 데이터들을 묶어서 클라이언트로 다시 보내준다.
type Query {
author(id: ID!): Author
}
type Author {
posts: [Post]
}
type Post {
title: String
content: String
}
query {
author(id: "abc") {
posts {
title
content
}
}
}
// 위의 쿼리의 필드들은 아래와 같이 schema에 정의된 type과 관계가 있다.
query: Query {
author(id: "abc"): Author {
posts: [Post] {
title: String
content: String
}
}
}
// Query.author에 대한 resolver를 실행한다. 그리고 얻어진 결과를 취하고,
// 그 아래의 필드에 대한 resolver로 넘긴다
Query.author(root, { id: 'abc' }, context) -> author
// parent에서 받은 결과값을
Author.posts(author, null, context) -> posts
for each post in posts
Post.title(post, null, context) -> title
Post.content(post, null, context) -> content
이건 ORM의 관점에서 조금 생각해보아야 하는데, 특정 id를 통해 Author를 조회한다고 가정하자. schema에 보면 Author는 post를 여러개 가지고 있다. 즉, 1 : N 관계를 가지고 있는 것이다. 그렇기 때문에 실제 데이터베이스에서 조회를 하기 위해서는 이 Author를 통해서 N쪽을 join해서 가져오게 되는데, 이와 비슷하게 resolver를 통해서 author를 가져오면, 해당 데이터를 가지고 post를 같이 가져와야하는 것이다.
#그래프큐엘