Hello, GraphQL

REST API
GET
/users/42
POST
/users
URI 와 Method를 통해 자원과 행위를 명확히 표현
Over-Fetching
서버에서 필요이상의 데이터를 받는 것
User 이름 목록을 보여주는 화면
/users 요청
address, age 등 부가 데이터도 같이 수신
Under-Fetching
특정 Endpoint에서 충분하지 못한 데이터를 리턴
User Profile 화면
/user/1, /feed, /follower 요청
API 하나 완성을 위해 몇 번의 요청을 하게된다.

이외에도..
CRUD 속하지 않는 행위
정보가 있다면 업데이트하고 없으면 추가 하는 Upsert
POST 를 써야 할까요? PUT을 써야될까요?
애매하니까 그냥 POST를 쓰자 !
팀마다 사용하는 방식이 다름 (명확하지 않은 표준)
RESTful 하다?
그런 REST API로 괜찮은가?
REST를 구성하는 스타일
- stateless
- cache
- uniform interface
- self-descriptive messages
- hypermedia as the engine of application state(HATEOAS)
- layered system
- code on demand (optional)
RESTful 한가요?
1. REST 하게 구현한다.
2. HTTP API 라고 부른다.
3. REST 하지 않지만 그냥 그렇게 부른다.
실제 다양한 요구사항을 해결하면서
REST 하게 개발하는것은 어렵다
REST API 이외에 대안은?
GraphQL

A Query language for your API
라이브러리 ❌
API 표준 ⭕️
🚩 Goal
- Eliminate Overfetching
- Eliminate Underfetching
- Be Declartive
Architecture


Client
GraphQL
Server

Query
Response
Query
Database
Response

REST API
Http Request
Http Response
DataSource 와 무관하게 사용가능
{
user {
name
}
}Flow
- 데이터가 어떤식으로 구성되어있는지 형식 정의
- 필요한 데이터를 기반으로 Query 작성
- 데이터를 어떻게 처리해서 보낼지 Code 작성
[
{
"id":1,
"name":"Leanne Graham",
"username":"Bret",
"email":"Sincere@april.biz",
"address":{
"street":"Kulas Light",
"suite":"Apt. 556",
"geo":{
"lat":"-37.3159",
"lng":"81.1496"
}
},
"phone":"1-770-736-8031 x56442"
},
{
"id":2,
"name":"Ervin Howell",
"username":"Antonette",
"email":"Shanna@melissa.tv",
"address":{
"street":"Victor Plains",
"suite":"Suite 879",
"geo":{
"lat":"-43.9509",
"lng":"-34.4618"
}
},
"phone":"010-692-6593 x09125"
}
]GET /users
application/json
response
REST API
{
user {
name
}
}Response
Basic Query
Request
[
{
"id":1,
"name":"Leanne Graham",
"username":"Bret",
"email":"Sincere@april.biz",
"address":{
"street":"Kulas Light",
"suite":"Apt. 556",
"geo":{
"lat":"-37.3159",
"lng":"81.1496"
}
},
"phone":"1-770-736-8031 x56442"
},
{
"id":2,
"name":"Ervin Howell",
"username":"Antonette",
"email":"Shanna@melissa.tv",
"address":{
"street":"Victor Plains",
"suite":"Suite 879",
"geo":{
"lat":"-43.9509",
"lng":"-34.4618"
}
},
"phone":"010-692-6593 x09125"
}
][
{
"name":"Leanne Graham",
"posts": {
"title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
"body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
}
},
{
"name":"Ervin Howell",
"posts": {
"title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
"body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
}
}
]{
user {
name
posts {
id
title
body
}
}
}Response
Basic Query - Relation
Request
Basic Query - Arguments
{
user(id: 1) {
name
posts {
id
title
body
}
}
}Request
[
{
"name":"Leanne Graham",
"posts": {
"title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
"body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
}
}
]Response
Type System
type User {
id: String!
name: String!
phone: String!
}Basic
type Starship {
id: ID!
name: String!
length(unit: LengthUnit = METER): Float
}Arguments
Schema
schema {
query: Query
mutation: Mutation
}Basic
Query
Mutation
질의를 위한 인터페이스
상태변화를 위한 인터페이스
Example Query Type
type Query {
users: [User]!
user(id: Int!): User!
posts: [Post]!
}
쿼리이름과 반환할 타입에 대한 정의
GraphQL Server Library(JS)
Demo Graphql-yoga
Graphql-yoga Setup
import { GraphQLServer } from "graphql-yoga";
import resolvers from './graphql/resolvers';
const server = new GraphQLServer({
typeDefs: './graphql/schema.graphql',
resolvers
});
server.start();- typeDefs - Graphql Type & Schema 정의
- resolvers - resolver를 정의
Define User & Post Type
type User {
id: Int!
name: String!
username: String!
email: String!
phone: String!
posts: [Post!]!
}
type Post {
id: Int!
title: String!
body: String!
user: User!
}
type Query {
users: [User]!
user(id: Int!): User!
posts: [Post]!
}
Resolvers
import { users, posts } from './db';
const resolvers = {
Query: {
users: () => users;
user: ( _, { id }) => users.find(u => u.id === id);
posts: () => posts;
},
Post: {
user: ({ userId }) => users.find(u => u.id === userId)
},
User: {
posts: ({ id }) => posts.filter(p => p.userId === id)
}
};
export default resolvers;
Playground

Query, Mutation 을 확인할 수 있음
graphql library 에서 제공
GraphQL 이점
- 자동 문서화 + 테스팅 도구 Playground
- 단일 Endpoint
- 타입 유효성 검사
- Overfetching, Underfetching 방지
- 유연함
GraphQL 고려해 볼점
- Relation으로 Fetching 을 할때 성능 최적화 문제
- FrontEnd 업무량 증가? 유연함?
- 보안 문제
Refs
- Front-End GraphQL Library
- Tutorial & Learning
끝
Hello, GraphQL
By y0c
Hello, GraphQL
- 237