Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/knu-k/graphql-ts-practica
To address the issues of over-fetching and under-fetching that commonly occur in REST APIs, we will configure GraphQL and then conduct performance analysis on it.
https://github.com/knu-k/graphql-ts-practica
apollo apollo-server backend es6 express graphql nodejs restapi typescript
Last synced: 3 months ago
JSON representation
To address the issues of over-fetching and under-fetching that commonly occur in REST APIs, we will configure GraphQL and then conduct performance analysis on it.
- Host: GitHub
- URL: https://github.com/knu-k/graphql-ts-practica
- Owner: KNU-K
- Created: 2024-06-21T18:35:11.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2024-06-24T14:17:45.000Z (7 months ago)
- Last Synced: 2024-10-17T23:04:20.236Z (3 months ago)
- Topics: apollo, apollo-server, backend, es6, express, graphql, nodejs, restapi, typescript
- Language: TypeScript
- Homepage:
- Size: 314 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## ๐๏ธ ์ ํด๋น ์ฃผ์ ์ ๋ํ ์์ ๋ฅผ ์ ์ํ๋๊ฐ?
- graphql์ด Rest API ์ Over-fetching / Under-fetching์ ์ผ๋ง๋ ์ ๋์ํ๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด์.
### Over-fetching์ด๋
๊ฐ์ ธ์จ ์ ๋ณด์์ ํ์ํ ์ ๋ณด๋ ํ์ ์ ์ผ ์๋ ์๋ค. ํ์ง๋ง Rest API๋ก ํธ์ถ์ ํ๊ฒ๋๋ฉด, ๋ถํ์ํ ์ ๋ณด๊น์ง ๊ฐ์ง๊ณ ์ค๋ ๊ฒฝ์ฐ๊ฐ ์๋ค ์ด๋ฅผ `Over-fetching` ์ด๋ผ๊ณ ํ๋ค.
> ์๋ฒ์ ์์์ด ๋ญ๋น๊ฐ ๋จ.
### Under-fetching์ด๋?
ํ๋ก ํธ์๋์ ํ๋์ ํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํด์ ํ๋กํ ์ ๋ณด, ๊ฒ์๋ฌผ ์ ๋ณด, ๋๊ธ ์ ๋ณด๋ฑ ๋ง์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ผํ์ง๋ง, Rest api์์๋ ์ด๋ฌํ ๊ฒ์ ๊ฐ ๋ถ๋ถ์ ๋ฐ๋ผ ์์ฒญํด์ผํ๋ค. ํ์ํ ์ ๋ณด๋ฅผ ํ๋ฒ์ ๊ฐ์ ธ์ค์ง ๋ชปํ๋ ๊ฒ์ `Under-fetching` ์ด๋ผ๊ณ ํ๋ค.
> ์๋ฒ์ ์์ฒญ๋์ด ์ฆ๊ฐํ๊ฒ ๋จ.
### GraphQL์ ๋ฑ์ฅ
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์, ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ํ์ํ ๊ฒ์ ์ต์ ํํ์ฌ ํ๋ฒ์ ์์ฒญ์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ค๋ ๊ฒ์ ์ฃผ ๋ชฉํ๋ก ํ์ฌ ๋ง๋ค์ด์ก๋ค.
`GraphQL`๊ณผ `SQL`์ ๊ฐ์ Query Language์ด๋ค. ๊ฐ๋จํ ๋งํด์ ์ง์ํ์ผ๋ก ์์ฒญํ์ฌ ํ์์ ๋ฐ๋ฅธ ์๋ต์ ๋ฐ์ ์ ์๋ ๊ฒ์ด๋ค.
## ๐ ch1. Query๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ
### hello world๋ฅผ ํด๋ณด์
```tsx
import express, { Application } from "express";
import { ApolloServer } from "@apollo/server";
import { expressMiddleware } from "@apollo/server/express4";const typeDefs = `#graphql
type Query {
hello: String
}
`;const resolvers = {
Query: {
hello: () => "world",
},
};export default async function createApp(): Promise {
const app = express();
const server = new ApolloServer({
typeDefs,
resolvers,
});await server.start();
app.use("/graphql", express.json(), expressMiddleware(server));return app;
}
```์์ ๊ฐ์ด ์ฝ๋๋ฅผ ๊ตฌ์ฑํ์๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก express๋ฅผ ์ฌ์ฉํ์ง์๊ณ graphQL๋ฅผ ์ ์ํ ์ ์์ง๋ง, express์ ํจ๊ป ์ ์ฐํ๊ฒ ๋์ํ๋ graphQL์ ์ฌ์ฉํ๋๋ก ํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ๋ค.
express์ ๋ฏธ๋ค์จ์ด๋ฅผ ํตํด์ resolver์ ์ ๊ทผํ์ฌ Query๋ฅผ ํ์ธ ํ ๋ต์ ์ค ์ ์๋ ๊ฒ์ด๋ค.
ํ์ฌ ์ฑํฐ์์ `npm test`๋ฅผ ํตํด์ ํ ์คํธ๋ฅผ ์งํํด๋ณด์.
```json
query : "query { hello }"
```๋ผ๋ ํ์์ ์ฟผ๋ฆฌ๋ฅผ json ํ์์ผ๋ก ๋ณด๋ด๊ฒ ๋๋ฉด, ์ผ๋ฐ Rest API์ ๊ฐ์ JSONํํ๋ก ์๋ต์ ๋ฐ์ ์ ์๊ฒ ๋๋ค. ํด๋น ํ ์คํธ๋ ์ด์ ๋ํ ๋ถ๋ถ์ ์ง๊ด์ ์ผ๋ก ํ์ธํ ์ ์๋๋ก ๊ตฌ์ฑํ๋ค..
## ๐ ch2. ๊ฐ๋จํ๊ฒ RestAPI ์ GraphQL ๊ฐ์ ๋น๊ต
์ด๊ธฐ ์ฑํฐ์์๋ database๋ฅผ ์ฌ์ฉํ์ง์๊ณ practice์ ๋ํด์ ์๊ฐํ๋ ค๊ณ ํ๋ค.
### ๐ฉ์ด๊ธฐ ์๋๋ฆฌ์ค ๊ตฌ์ฑ
ํ๋กํ ์ ๋ณด, ๊ฒ์๋ฌผ, ๋๊ธ์ ํ๋ก ํธ์์ ์์ฒญ์ด ํ์๋ก ํ ๋:
- REST API : ํ๋กํ ์ ๋ณด, ๊ฒ์๋ฌผ, ๋๊ธ์ ๋ํ ์์ฒญ์ ๋ฐ๋ก ๊ตฌ์ฑํ๋ค.
- GraphQL : Query ๊ธฐ๋ฐ์ผ๋ก ํ๋ฒ์ ์์ฒญ์ผ๋ก ๊ฐ๋ฅํ๊ฒ ํ ์ ์๋ค.### ๐ดREST API๋ก ๊ตฌ์ฑ
`/api/profile`
`/api/board/:id`
`/api/comment`
๋ก ๊ตฌ์ฑํ ๊ฒ์ด๋ค. ํ์ฌ๋ ์ธ์ฆํ๋ ๊ฒ์ด ๋ชฉ์ ์ด ์๋๊ธฐ ๋๋ฌธ์, ์ธ์ฆ๋ถ ์์ด ๋ฌด์กฐ๊ฑด์ ์ผ๋ก 1๋ฒuser์ profile์ ์ฃผ๋๋ก ํ๊ฒ ๋ค.### ๐ณ๏ธGraphQL๋ก ๊ตฌ์ฑ
```graphQL
query {
userProfile(id: 1) {
id
name
age
phone
}
getBoard(id:1){
postId
userId
title
content
timestamp
}
getComment(boardId:1){
commentId
postId
userId
content
timestamp
}
}
```ํด๋น ์ฟผ๋ฆฌ๋ฅผ ํตํด ํ๋ฒ์ ์ ๊ทผ ๊ฐ๋ฅ, ํด๋น ๋ถ๋ถ์์๋ ์ค๋ช ์ ๋ถํ์ํ ๋ด์ฉ์ ์ ์ธํ์ฌ ์งํํ๋ค.
### โ ๊ฐ๋จํ ๋น๊ต ๋ถ์
#### : ํด๋ผ์ด์ธํธ๊ฐ ์ํ๋ ์๋ต์ ์ค๋นํ ์ ์๋ graphQL
`Rest API` ๋ ์๋ฒ๊ฐ ๊ตฌ์ฑํ๊ณ ์๋ ํํ๋ฅผ ํด๋ผ์ด์ธํธ์ ํ์์ ๋ฐ๋ผ ๋ณ๊ฒฝํ๋ ค๋ฉด ์๋ก์ด api ๋ฅผ ๊ตฌ์ฑํด์ผํ๋ ๋ฒ๊ฑฐ๋ฌ์์ด ์กด์ฌํ ์ ์๋ค.
ํ์ง๋ง, `GraphQL`์ ๊ฒฝ์ฐ์๋ ๊ทธ ๋ ๊ทธ๋ ํ์ํ ์ธ์๋ง์ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์, ์๋ต์ ๋ฐ๋ ๊ฒ์ ์์ ๋กญ๋ค.
#### : ๊ณผ์ฐ ์๋ต ์๋๊ฐ ์ ๋ง ๋น ๋ฅผ๊น? ์ค์ ์คํ์ ํด๋ณด์
`Rest API` ์ `GraphQL`์์ ์์ฒญ์ ๋ฐ๋ฅธ ์๋ ์ฐจ์ด๊ฐ ๋ํ๋ ์๋ ์๋ค๊ณ ํ๋๋ฐ, ์ ๋ง์ธ์ง ํ์ธํ๊ธฐ ์ํด์ ๋์ผ ์๋ฒ ์คํ์์ ์ด 5๋ฒ์ ํ ์คํธ๋ฅผ ์งํํด๋ดค๋ค.
`npm test perform`์ ํตํด์ ์ด๋ฅผ ํ์ธํ ์ ์๋ค!
perform์ ๋ํ test๋ฅผ ์งํํ ๊ฒฐ๊ณผ 1.3 ~ 1.7 ๋ฐฐ ๋ ๋น ๋ฅธ ๊ฒ์ผ๋ก ์ธก์ ๋์๋ค. ์ด๋ ๊ฒ ํ ๋ฒ์ ๋ง์ ์์ฒญ๋์ด client๊ฐ ํ์๋ก ํ๋ค๊ณ ์๊ฐํ๋ฉด ํธํ ๊ฒ์ด๋ค.
> ๋ง์ ํด๋ผ์ด์ธํธ๋ ํ๋์ ํ์ด์ง ๋จ์์ ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฅผ ์ป๊ธฐ ์ํ ์๋ก ๋ค๋ฅธ api์์ฒญ์ ๋ฐ๋ณตํ๋ค.
## ๐ ch3. Under-Fetching๊ณผ Over-Fetching์ ๋ํ ์ฌ๋ก์ GraphQL์ ํตํ ๊ทน๋ณต
### โฌ๏ธ Under-Fetching & ๐ Over-Fetching
GraphQL์ด Rest API์ Under-Fetching๊ณผ Over-Fetching ๊ฐ์ ์ํฉ์ ์ผ๋ง๋ ์ ๊ทน๋ณตํ๋์ง์ ๋ํด์ ์๊ฐํ๋ ค๊ณ ํ๋ค.
`Under-Fetching`๋ ์์ ์์ ์ ๋น์ทํ๋ค.
๋จผ์ REST ๊ตฌ์กฐ๋ฅผ ์์์ผ๋ก GraphQL๊น์ง ์์ฑํด๋ณด์.
#### ๐ฉUnder-Fetching ์๋๋ฆฌ์ค
์ฌํ ๋ฆฌ๋ทฐ ์น์ฌ์ดํธ์์ ์ฌ์ฉ์์ ํ๋กํ ์ ๋ณด๋ฅผ ํฌํจํ ํน์ ์ฌ์ฉ์์ ์์ฑํ ๋ฆฌ๋ทฐ ๋ชฉ๋ก์ ํด๋ผ์ด์ธํธ์์ ์์ฒญํ๋ ์ํฉ์ ๊ณ ๋ คํด๋ณด์. ์ฌ์ฉ์๋ ์ฌ๋ฌ ๋ฆฌ๋ทฐ๋ฅผ ์์ฑํ ์ ์์ผ๋ฉฐ, ๊ฐ ๋ฆฌ๋ทฐ์๋ ์์ฑ์์ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์๋ค.
#### ๐ฉOver-Fetching ์๋๋ฆฌ์ค
ํ์ฌ ์น์์ ์ฌ์ฉ์์ ๋ํ ๊ธฐ๋ณธ ์ ๋ณด (์ด๋ฆ๊ณผ ์ด๋ฉ์ผ)๋ง์ ๋ณด์ฌ์ฃผ๋ ค๊ณ ํ๋ค. ํด๋น ์ฌํญ์ ๊ณ ๋ คํด๋ณด์.
#### ๐๏ธ ์๊ตฌ์ฌํญ์ ๋ฐ๋ฅธ ํ์ ์์ ์ถ์ถ
์ฌ๊ธฐ์ ํ์ํ ๋ถ๋ถ์ ์ถ์ถํด๋ณด๋ฉด ์๋์ ๊ฐ๋ค.
- RestAPI
- ์ ์ ์ ์ฒด ์ ๋ณด - `/api/user`
- ์ ์ ํ๋กํ ์ ๋ณด - `/api/user/:userId`
- ์ฌ์ฉ์ ๋ฆฌ๋ทฐ ๋ชฉ๋ก - `/api/user/:userId/review`
- ๋ฆฌ๋ทฐ ์์ธ ์ ๋ณด - `/api/review/:reviewId`
- GraphQL- typeDef Schema
```tsx
export default `#graphql
type User {
id: Int!
name: String!
email: String!
reviews: [Review]
}
type Review {
reviewId: Int!
content: String!
score: Int!
timestamp: String!
author: User
}
type Query {
user(id: Int): User
users: [User]
userReviews(userId: Int!): [Review]
review(id: Int!): Review
}
`;
```> - ์ด๋ฌํ Schema ๊ตฌ์กฐ๋ก ์ด๋ ํ ๋ฐ์ดํฐ๋ฅผ ์ํธ๊ตํํ ์ง ํ๊ธฐํจ.
> - `reviews:[Review]`์ ๊ฐ์ Recursiveํ ๊ตฌ์กฐ ๋ํ ๊ฐ๋ฅ์์ ๊ฐ์ ํํ๋ก ๊ตฌ๋ถ์ด ๊ฐ๋ฅํ๋ค. ๋ณธ ์ฑํฐ๋ถํฐ ์์ ๋ ๊ฐ๋ ์ฑ์ ์ํด ๋ชจ๋ํ๋ฅผ ์งํํ๋ฉด์ ๊ตฌ์กฐํ๋ฅผ ํ๋๋ก ํ๊ฒ ๋ค.
#### ๐ ํด๋ ๊ตฌ์กฐ
- graphql
- loader
- express.ts
- graphql.ts
- index.ts
- schema
- resolver.ts
- typeDefs.ts
- app.ts
- restapi
- api
- routes
- review.ts
- user.ts
- index.ts
- loaders
- index.ts
- app.ts#### ๐ซperformance
- Under-Fetching
| Test Description | REST API Performance (ms) | GraphQL API Performance (ms) |
| ------------------- | ------------------------------------------ | ------------------------------------------- |
| Measure Performance | 38.17 | 14.33 |
| Image Data | ![alt text](./images/ch3-rest-perform.png) | ![alt text](./images/ch3-graph-perform.png) |- Over-Fetching
| Test Description | REST API Performance (ms) | GraphQL API Performance (ms) |
| ------------------- | ------------------------------------------- | -------------------------------------------- |
| Measure Performance | 9.13 | 20.4 |
| Image Data | ![alt text](./images/ch3-rest-perform2.png) | ![alt text](./images/ch3-graph-perform2.png) |`npm test perform`์ ํตํด ์ฑ๋ฅ์ ์ธก์ ํด๋ณผ ์ ์์ ๊ฒ์ด๋ค.
#### ๐ซ์ฑ๋ฅ์ ๋ํ ์ฐจ์ด๊ฐ ์กด์ฌํ๋ ์ด์
๊ฐ๋จํ๊ฒ ์์๋ฅผ ๋ค์ด์ฃผ๊ฒ ๋ค. ์ด ๊ฒ์ ๋ง์น Buffering ๊ฐ๋ ๊ณผ ๋น์ทํ๋ค. ๊ณ๋์ ๊ฐ์ง๊ณ ์ฌ ๋, `๋ฐ๊ตฌ๋๋ฅผ ๊ฐ์ง๊ณ ํ๋ฒ์ ๊ฐ์ ธ์ค๋ ๊ฒ`๊ณผ `1๊ฐ์ฉ ์๋ค๊ฐ๋ค ํ๋ฉด์ ๊ฐ์ ธ ์ค๋ ๊ฒ` ๋ฑ GraphQL๊ณผ Rest API๋ ํด๋น ์์์ ๊ฐ์ ์ฐจ์ด๊ฐ ๋๋ค.
**_Under-Fetching์ ๊ฒฝ์ฐ_** ๋ REST API ์์ ํ์๋ก ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ป๊ธฐ ์ํด์๋ ์ฌ๋ฌ๋ฒ์ ์์ฒญ์ด ํ์ํ ๊ฒ์ด๋ค. ๊ฒฐ๊ตญ ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ์ป๋๋ค๊ณ ๊ฐ์ ํ๋ฉด `์๋ค ๊ฐ๋ค๊ฑฐ๋ฆฌ๋ ์๊ณ `๋ง ๋ ์ถ๊ฐ ๋ ๊ฒ์ด๋ค.
์ด ๊ฒ์ด ๊ฐ๋จํ ๋งํด ์ฑ๋ฅ์ฐจ์ด์ ํฐ ์์ธ์ด ๋ ๊ฒ์ด๋ค.
์ด๋ ๊ฒ ๋งํ๋ฉด graphql ๋งน์ ๋ก ์์ ๊ฐ์ด ๋๊ปด์ง ์๋ ์์ง๋ง, ๊ทธ๋ ์ง๋ ์๋ค. ์ฟผ๋ฆฌ ๊ตฌ์กฐ๊ฐ ์์ง๊น์ง ๋จ์ํด์ ๊ด์ฐฎ์ง๋ง, ์์ `recursive ํ ๊ตฌ์กฐ๋ฅผ ํ์ฉ`ํ๋ค๋ ๋ง์ ๋ดค๋ค๋ฉด ์์ํ๊ฒ ์ง๋ง, ์ฟผ๋ฆฌ ๊ตฌ์กฐ๊ฐ ๋ณต์กํด์ง ์๋ก graphql ์์์ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ ์ ์๋ค๋ ์ ๋ ์ผ๋ํด๋๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
๊ทธ๋ฌํ ์ค๋ฒํค๋๋ฅผ ์ ์ธํ๋ฉด ๋ง์ ์ด์ ๋ค์ด ์กด์ฌํ๋ค.
1. ๋ณต์ ์์ฒญ์ ๊ฐ์
2. ์ ํํ ๋ฐ์ดํฐ ์์ฒญ (ํ์ํ ๋ฐ์ดํฐ๋ง ๊ฐ๋ฅ)
3. ๋คํธ์ํฌ ํธ๋ํฝ ๊ฐ์(๋จ์ผ ์์ฒญ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์๊ธฐ ๋๋ฌธ์)์ด๋ฌํ, ์ด ์ ์ ์คํ๋ ค ๋ค์ํ ์๋น์ค๋ฅผ ๋ง๋๋๋ฐ ํฐ ๋์์ ์ค ๊ฒ์ด๋ผ ํ์ ํ๋ค.
**Over-Fetching ์์ ์ ๊ฒฝ์ฐ**๋ graphql์์ `์ค๋ฒํค๋`๊ฐ ๋ฐ์ํ๋ ์ข์ ์ฌ๋ก๋ผ๊ณ ์๊ฐํ๋ค.
> ๋ค๋ฅธ ์ฌ๋๋ค: ๋ฐฉ๊ธ๊น์ง๋งํด๋ GraphQl์ด ์ข๋ค๊ณ ํ์์์!
> **๋ฌผ๋ก ์ด๋ค. ํ์ง๋ง ์ค๋ฒํค๋๋ฅผ ๊ณ ๋ คํด์ผํ๋ค.**
์ฌ๊ธฐ์ ์ ๊น ์ฃผ๋ชฉํ๋ฉด ์ข์ ์ ์ Response Size์ด๋ค. GraphQL์ด Rest API ๋ณด๋ค ํจ์ฌ ์ ๋ค. ํ์ฌ ์คํ ์์ฒด๋ Local์์ ์งํํ์ง๋ง, ์ฌ๋ฌ remote ํต์ ์ด ์์ ๋ Response Size๊ฐ ๋ฎ์ ์ฆ, "๋์ญํญ"์ด ๋ฎ์ GraphQL์ด ์ ๋ฆฌํด์ง ์ ์๋ค.
#### GraphQL์ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ๋ ์ด์
GraphQL์์ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ๋ ์ด์ ๋ ์ฟผ๋ฆฌ๋ฅผ ํตํ ์ง์๋ ์๊ตฌ์ ๋ง๊ฒ ๋ฐ์ดํฐ ํด์๊ณผ์ ์ ๊ฑฐ์น๊ธฐ ๋๋ฌธ์ ์๋ตํ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์ด๋ด๋๋ฐ๊น์ง ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฌ๋ ๊ฒ์ด๋ค.
์ด๋ฅผ ์ฟผ๋ฆฌ ์ต์ ํ, Resolver ์ต์ ํ ๋ฑ๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ํด์ํ ์ ์๋ค. ์ด๋ ์ถํ ์ฑํฐ์์ ์๊ฐํ ์์ ์ด๋ค.
์ง๊ธ๊น์ง์ ๋ด์ฉ์ผ๋ก ์์์ผ๋ฉด ์ข๊ฒ ๋ ์ ์ ์๋ก๊ฐ์ **ํธ๋ ์ด๋ ์คํ**๊ฐ ๋ถ๋ช ์กด์ฌํ๋ค๋ ๊ฒ์ด๋ค.