티스토리 뷰
graphQL이란?
그래프 QL은 페이스북이 2012년에 개발하여 2015년에 공개적으로 발표된 데이터 질의어이다. 그래프 QL은 REST 및 부속 웹서비스 아키텍처를 대체할 수 있다. 클라이언트는 필요한 데이터의 구조를 지정할 수 있으며, 서버는 정확히 동일한 구조로 데이터를 반환한다.
장점
1. Overfetching을 없앨 수 있다.
예를 들어 모든 사용자 이름을 GET으로 가져오는데 사용자 이름과 더불어 프로필 사진, 전화번호, 이메일 등 필요한 정보보다 더 많이 서버로부터 받는 것을 Overfetching이라고 하는데 graphQL을 사용한다면 필요한 정보만 가져올 수 있어서 Overfetching을 막을 수 있다.
2. UnderFetching을 막을 수 있다.
UnderFetching이란 화면을 구성하는데 유저의 API , 알림 API , 글 목록 API 등 3가지의 API를 받아서 화면을 구성해야만 화면을 띄울 수 있다면 이런 것이 underFetching이라고 한다. graphQL을 사용한다면 한 쿼리에 정확한 정보만 담아서 이용할 수 있게 된다.
23년도 아폴로 서버 사용 방법
npm i apollo-server graphql
Apollo 서버는 Apollo 클라이언트를 포함한 모든 GraphQL 클라이언트와 호환되는 오픈 소스 사양 호환 GraphQL 서버입니다. 모든 소스의 데이터를 사용할 수 있는 프로덕션 준비가 된 자체 문서화 GraphQL API를 구축하는 가장 좋은 방법입니다.
Schema
typeDefs에 무조건 Query라는 타입이 있어야 합니다. rest API로 치자면 /allTweets , /tweet/:id와 같이 URL에서 찾아주는 역할을 하는 타입이라고 합니다. 또한 아폴로 서버에서 제공하는 사이트를 이용해서 API를 테스트해 볼 수 있습니다.
server.js
import { ApolloServer, gql } from 'apollo-server';
const typeDefs = gql`
type User {
id: ID
username: String
}
type Tweet {
id: ID
text: String
author: User
}
type Query {
allTweets: [Tweet]
tweet(id: ID): Tweet
}
`;
const server = new ApolloServer({ typeDefs });
server.listen().then(({ url }) => {
console.log(`Running on ${url}`);
});
Mutation
graphQL에서는 Query 혹은 Mutation 둘 중 하나만 사용합니다.
Query는 RestAPI에서 GET의 역할을 합니다.
Mutation은 RestAPI에서 PUT, POST, DELETE의 역할을 합니다.
const typeDefs = gql`
type User {
id: ID
username: String
}
type Tweet {
id: ID
text: String
author: User
}
type Query {
allTweets: [Tweet]
tweet(id: ID): Tweet
}
type Mutation {
postTweet(userId: ID, text: String): Tweet
deleteTweet(id: ID): Tweet
}
`;
! 의 유무
! 는 Null일수도 있는지 아닌지 체크해 주는 역할입니다.! 를 붙이면 불러오고자 하는 대상이 Null일 때 에러로 개발자에게 알려줍니다.
type Tweet {
id: ID! // id는 Null 값이 아니다
text: String // text는 String 값이거나 Null 값이다.
author: User // author는 User 이거나 Null 값이다.
}
Resolvers
resolver 함수는 데이터베이스에 액세스 한 다음 데이터를 반환합니다.
import { ApolloServer, gql } from 'apollo-server';
const tweets = [
{
id: '1',
text: 'first one!',
},
{
id: '2',
text: 'second one',
},
];
const typeDefs = gql`
type User {
id: ID
username: String
}
type Tweet {
id: ID!
text: String
author: User
}
type Query {
allTweets: [Tweet]
tweet(id: ID): Tweet
}
type Mutation {
postTweet(userId: ID, text: String): Tweet
deleteTweet(id: ID): Tweet
}
`;
const resolvers = {
Query: {
allTweets() {
return tweets;
},
tweet(root, { id }) {
return tweets.find(tweet => tweet.id === id);
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Running on ${url}`);
});
Resolvers Args
첫 번째 인자인 root는 자신을 포함하고 있는 부모를 뜻합니다. 두 번째 인자는 Mutation에서 인자로 id, text 등을 주었을 때 두 번째 인자에서 확인할 수 있습니다.
const users = [
{
id: '1',
firstName: 'Kim',
lastName: 'YoungGil',
},
];
const typeDefs = gql`
type User {
id: ID
firstName: String
lastName: String
fullName: String
}
type Query {
allUsers: [User]
}
`;
const resolvers = {
Query: {
allUsers() {
return users;
},
},
User: {
fullName(root) {
console.log(root); // { id: '1', firstName: 'Kim', lastName: 'YoungGil' }
return `${root.firstName} ${root.lastName}`;
},
},
};
RelationShip
Resolvers의 첫 번째 인자인 root를 이용해서 RelationShip을 설정할 수 있습니다.
const tweets = [
{
id: '1',
text: 'first one!',
userId: '2',
},
{
id: '2',
text: 'second one',
userId: '1',
},
];
const users = [
{
id: '1',
firstName: 'Kim',
lastName: 'YoungGil',
},
];
const resolvers = {
Query: {
Tweet: {
author({ userId }) { // 유저들에서 글쓴이의 아이디와 비교하여 동일한 아이디를 찾아 리턴함
return users.find(user => user.id === userId);
},
},
User: {
fullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
},
},
};
Documentaion
설명하고자 하는 타입 위에 """ 할 말 """을 하게 된다면 쉽게 문서화가 가능합니다.
const typeDefs = gql`
"""
유저에 관한 타입 설명입니다
"""
type User {
id: ID
firstName: String
lastName: String
fullName: String
}
type Tweet {
id: ID!
text: String
author: User
}
type Query {
"""
모든 트위터에 대한 설명입니다
"""
allTweets: [Tweet]
tweet(id: ID): Tweet
allUsers: [User]
}
type Mutation {
postTweet(userId: ID, text: String): Tweet
deleteTweet(id: ID): Tweet
}
`;
REST API --> graphQL로 변환하기
이 사이트에서 쉽게 변환할 수 있습니다. 타입을 graphQL으로 지정한 뒤 resolver을 사용해 활용하면 됩니다.
type Query {
allMovies: [Movie!]!
allUsers: [User!]!
allTweets: [Tweet!]!
tweet(id: ID!): Tweet
movie(id: String!): Movie
}
///
resolver .
{
allMovies() {
return fetch("https://yts.mx/api/v2/list_movies.json")
.then((r) => r.json())
.then((json) => json.data.movies);
},
movie(_, { id }) {
return fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
.then((r) => r.json())
.then((json) => json.data.movie);
},
}
22년도 요가 사용 방법
yarn add graphql-yoga
https://www.npmjs.com/package/graphql-yoga
CRA로 리액트 프로젝트를 만들듯이 graphql 프로젝트를 쉽게 사용하도록 도와주는 라이브러리입니다.
Schema
컴퓨터 과학에서 데이터베이스 스키마는 데이터베이스에서 자료의 구조, 자료의 표현 방법, 자료 간의 관계를 형식 언어로 정의한 구조이다.
shema.graphql 파일을 만들어서 타입 스크립트에서 interface를 만드는 것처럼 type 지정을 해주어야 합니다.
type Person {
id: Int!
name: String!
age: Int!
gender: String!
}
type Query {
people: [Person]!
person(id: Int!): Person
}
Resolvers
Apollo Server는 스키마의 모든 필드에 데이터를 채우는 방법을 알고 있어야 데이터 요청에 응답할 수 있습니다. 이를 위해 리졸버를 사용합니다.
리졸버는 스키마의 단일 필드에 대한 데이터를 채우는 함수입니다. 백엔드 데이터베이스 또는 타사 API에서 데이터를 가져오는 등 사용자가 정의하는 모든 방법으로 데이터를 채울 수 있습니다.
요약하자면 어떤 데이터를 사용할지 정하는 방법입니다.
서버를 작동
import { GraphQLServer } from "graphql-yoga";
import resolvers from "./graphql/resolvers";
console.log("hi");
const server = new GraphQLServer({
typeDefs: "graphql/schema.graphql",
resolvers,
});
server.start(() => console.log("Server is running on localhost:4000"));
localhost:4000에서 playground graphQL을 사용할 수 있습니다.
graphQl의 장점으로는 query 하나만으로 원하는 데이터를 가져올 수 있다는 점입니다.
원하는 정보 조회
원하는 아이디를 찾아서 조회할 수 있습니다.
import { people } from "../db/db";
const getById = (id) => {
const person = people.filter((item) => item.id === id);
return person[0];
};
const resolvers = {
Query: {
people: () => people,
person: (_, { id }) => getById(id),
},
};
export default resolvers;
Mutation
GraphQL에 대한 대부분의 논의는 데이터 취득에 초점을 맞추고 있지만 완전한 데이터 플랫폼에는 서버 측 데이터도 수정할 수 있는 방법이 필요합니다.
REST에서는 어떤 요구도 서버에 부작용을 일으킬 수 있지만, 관례상 GET 요청을 사용하여 데이터를 수정하지 않는 것이 좋습니다. GraphQL은 비슷합니다. 기술적으로는 데이터 쓰기를 유발하기 위해 어떤 쿼리도 구현할 수 있습니다. 그러나 쓰기를 유발하는 모든 작업은 변환을 통해 명시적으로 전송해야 한다는 규칙을 설정하는 것이 유용합니다.
쿼리와 마찬가지로 변환 필드가 개체 유형을 반환하는 경우 중첩된 필드를 요청할 수 있습니다. 이 기능은 업데이트 후 개체의 새 상태를 가져올 때 유용합니다.
API를 이용할 때 새로운 데이터를 추가하거나 삭제, 수정해야 할 경우가 있는데 이럴 때 사용 가능한 것이 Mutation입니다.
addMovie는 함수로 만들어서 사용합니다. API 관리하는데 엄청 편한 것 같습니다.
let movies = [
{
id: 0,
name: "Star Wars - The new one",
score: 1,
},
{
id: 1,
name: "Avengers - The new one",
score: 8,
},
{
id: 2,
name: "The Godfather I",
score: 99,
},
{
id: 3,
name: "Logan",
score: 2,
},
];
export const getMovies = () => movies;
export const getById = (id) => {
const filteredMovies = movies.filter((movie) => movie.id === id);
return filteredMovies[0];
};
export const deleteMovie = (id) => {
const cleanedMovies = movies.filter((movie) => movie.id !== id);
if (movies.length > cleanedMovies.length) {
movies = cleanedMovies;
return true;
} else {
return false;
}
};
export const addMovie = (name, score) => {
const newMovie = {
id: `${movies.length + 1}`,
name,
score,
};
movies.push(newMovie);
return newMovie;
};
GraphQL을 사용해 보니 기존의 REST API에서 사용했었던 방식이 조금 불편해지지 않을까라고 생각이 되고 그만큼 잘 개발되어 만들어진 것 같다고 느꼈습니다. 앞으로 개인적인 프로젝트가 있다면 GraphQL방식을 사용해 볼 것 같습니다.
'자바스크립트' 카테고리의 다른 글
javascript ERROR Handler Function 템플릿 (0) | 2022.12.16 |
---|---|
Prettier + ESLint + Airbnb Style을 package.json 변경없이 셋팅하는 방법 (0) | 2022.12.12 |
리액트 Google 로그인 기능 OAuth 만들기 소셜 로그인 (0) | 2022.03.06 |
redux 개념 알아보기 && javascript 에서 리덕스 설치 및 이용하기 (0) | 2022.02.10 |
두 개의 데이터([{데이터}*20])를 통해 한 개의 데이터로 합치는 방법 (0) | 2021.12.12 |
- Total
- Today
- Yesterday
- 북클럽
- 노개북
- electron
- CLASS
- 아차산
- Storybook
- nodejs
- 프론트앤드
- TopLayer
- NextApiRequest
- 위코드
- javascript
- error
- 우아한테크코스
- 노마드코더
- env
- React
- 윤성우 열혈C프로그래밍
- 초보
- 원티드
- NextRequest
- jest
- nextjs
- createPortal
- 프리온보딩
- 스토리 북
- WSL2
- import/order
- C언어
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |