- Published on
express에서 graphql 사용하기
GraphQL은 Server API를 구성하기 위해 Facebook에서 만든 Query Language로, 정보를 사용하는 측에서 원하는 대로 가져올 수 있고, 보다 편하게 정보를 수정할 수 있도록 하기 위해 만들어졌다.
Facebook에서는 다음과 같은 이유로 GraphQL을 만들었다고 한다.
- RESTful API 로는 다양한 기종에서 필요한 정보들을 일일히 구현하는 것이 힘들었다.
- 예로, iOS 와 Android 에서 필요한 정보들이 조금씩 달랐고, 그 다른 부분마다 API 를 구현하는 것이 힘들었다.
RESTful과 차이점
- GraphQL API 는 주로 하나의 Endpoint 를 사용한다.
- GraphQL API 는 요청할 때 사용한 Query 문에 따라 응답의 구조가 달라진다.
GraphQL 장단점
장점
-
HTTP 요청의 횟수를 줄일 수 있다.
- RESTful 은 각 Resource 종류 별로 요청을 해야하고, 따라서 요청 횟수가 필요한 Resource 의 종류에 비례한다.
- 반면 GraphQL 은 원하는 정보를 하나의 Query 에 모두 담아 요청하는 것이 가능하다.
-
HTTP 응답의 Size 를 줄일 수 있다.
- GraphQL 은 필요한 정보만 부분적으로 요청하는 것이 가능하다.
단점
-
File 전송 등 Text 만으로 하기 힘든 내용들을 처리하기 복잡하다.
-
고정된 요청과 응답만 필요할 경우에는 Query 로 인해 요청의 크기가 RESTful API 의 경우보다 더 커진다.
-
브라우저캐시를 사용할 수 없다. graphQL은 모든 요청을 POST로 보내기 때문에 GET요청만 처리하는 브라우저 캐시를 사용할 수 없다. (Apollo client cache 등을 사용해야 한다.)
GraphQL or RESTful?
GraphQL사용
- 서로 다른 모양의 다양한 요청들에 대해 응답할 수 있어야 할 때
- 대부분의 요청이 CRUD(Create-Read-Update-Delete) 에 해당할 때
RESTful사용
- HTTP 와 HTTPs 에 의한 Caching 을 잘 사용하고 싶을 때
- File 전송 등 단순한 Text 로 처리되지 않는 요청들이 있을 때
- 요청의 구조가 정해져 있을 때
express에서 GraphQL API 구현
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLList,
GraphQLInt,
GraphQLNonNull,
} = require('graphql');
const app = express();
const authors = [
{ id: 1, name: 'Row' },
{ id: 2, name: 'Tolk' },
{ id: 3, name: 'Brent' },
];
const books = [
{ id: 1, name: 'Harry1', authorId: 1 },
{ id: 2, name: 'Harry2', authorId: 1 },
{ id: 3, name: 'Harry3', authorId: 1 },
{ id: 4, name: 'Harry4', authorId: 2 },
{ id: 5, name: 'Harry5', authorId: 2 },
{ id: 6, name: 'Harry6', authorId: 2 },
{ id: 7, name: 'Harry7', authorId: 3 },
{ id: 8, name: 'Harry8', authorId: 3 },
];
const AuthorType = new GraphQLObjectType({
name: 'Author',
description: 'This represents a author of a book',
fields: () => ({
id: { type: GraphQLNonNull(GraphQLInt) },
name: { type: GraphQLNonNull(GraphQLString) },
books: {
type: GraphQLList(BookType),
resolve: (author) => {
return books.filter((book) => book.authorId === author.id);
},
},
}),
});
const BookType = new GraphQLObjectType({
name: 'Book',
description: 'This represents a book written by an author',
fields: () => ({
id: { type: GraphQLNonNull(GraphQLInt) },
name: { type: GraphQLNonNull(GraphQLString) },
authorId: { type: GraphQLNonNull(GraphQLInt) },
author: {
type: AuthorType,
resolve: (book) => {
return authors.find((author) => author.id === book.authorId);
},
},
}),
});
const RootQueryType = new GraphQLObjectType({
name: 'Query',
description: 'Root Query',
fields: () => ({
book: {
type: BookType,
description: 'A Single Book',
args: {
id: { type: GraphQLInt },
},
resolve: (parent, args) => books.find((book) => book.id === args.id),
},
books: {
type: new GraphQLList(BookType),
description: 'List of All Books',
resolve: () => books,
},
authors: {
type: new GraphQLList(AuthorType),
description: 'List of All Authors',
resolve: () => authors,
},
author: {
type: AuthorType,
description: 'A Single Author',
args: {
id: { type: GraphQLInt },
},
resolve: (parent, args) => authors.find((author) => author.id === args.id),
},
}),
});
const RootMutationType = new GraphQLObjectType({
name: 'Mutation',
description: 'Root Mutation',
fields: () => ({
addBook: {
type: BookType,
description: 'Add a book',
args: {
name: { type: GraphQLNonNull(GraphQLString) },
authorId: { type: GraphQLNonNull(GraphQLInt) },
},
resolve: (parent, args) => {
const book = { id: books.length + 1, name: args.name, authorId: args.authorId };
books.push(book);
return book;
},
},
addAuthor: {
type: AuthorType,
description: 'Add an author',
args: {
name: { type: GraphQLNonNull(GraphQLString) },
},
resolve: (parent, args) => {
const author = { id: authors.length + 1, name: args.name };
authors.push(author);
return author;
},
},
}),
});
const schema = new GraphQLSchema({
query: RootQueryType,
mutation: RootMutationType,
});
app.use(
'/graphql',
graphqlHTTP({
schema,
graphiql: true,
})
);
app.listen(5000, () => console.log('Server Running'));