당신이 RESTful API 를 통해서 데이터를 받을 때,
다음과 같은 상황이 있었을 것이다.
그런데 이 모든 경우에 우리는 불필요할 정도로 많은 데이터를 받아야 한다.
그것은 기본적으로 RESTful API 가 json 타입으로 정보를 넘겨주기 때문이기도 하다.
아래에서 1번 Over-fetching 과 2번 Under-fetching 에 대해서 자세히 알아보도록 하겠다.
당신은 mongoDB 를 사용하고 있고 mongoose 의 Schema 기능을 통해 다음과 같은 데이터 모델을 다루고 있다. express 를 통해서 프로젝트 셋팅이 끝났다는 전제를 하고 있으며 Controller 에서 데이터 요청을 하는 상황이다. View Template 로는 [PUG]를 사용하고 있다.
- userSchema && userModel(User)
const userSchema=mongoose.Schema({ email: {type:String, required:true}, username: {type:String, required:true}, password: {type:String, required:true}, description: {type:String}, imageArray: [ {type:mongoose.Schema.Types.ObjectId, ref:"Image"} ], }); const userModel=mongoose.model("User",userSchema);
- imageScheam && imageModel(Image)
const imageSchema=mongoose.Schema({ title: {type:String, required:true, default:"untitled"}, imageURL: {type:String, required:true, default:null}, owner: {type:mongoose.Schema.Types.ObejctId, ref:"User"}, }); const imageModel=mongoose.model("Image",imageSchema);
한 대상에서 일부분의 데이터만 필요한 경우에도, 해당 대상의 모든 데이터를 받게 되는 문제점
당신은 유저 검색과 관련된 Controllers 를 만들어야 한다.
당신이 [H] 를 입력하면 유저 이름에 [H]가 들어간 사람을 찾는 것이다.
import userModel from "../model/userModel";
export const searchUserGet=async(req,res)=>{
const { saerch:username }=req.body;
const userDB=await userModel.findOne({username});
return (userDB) ?
res.render(".../view/screen/searchPage.pug",{ userDB }) :
res.render(".../view/screen/searchPage.pug",{ userDB:null, error:"404 Not Found"});
};
위 코드를 통해 당신은 다음과 같은 유저 배열을 얻게 되었다.
const userDB=[
{
id:124151351421
email:"Anonymous001@gmail.com",
username:"Anonymous001",
password:"malktmkqelmtlkeqm",
description:"I'm anonymous! Nice to meet you",
imageArray:[]
},
{
id:521513214122
email:"Hello@gmail.com",
username:"Hello",
password:"qtklmeqkltmkqler"
description:"Hello It's a Test Object Array",
imageArray:[ObjectId(142142151),ObjectId(15125124)]
}
];
그런데 당신의 View Template 에서는 다음의 정보만을 사용한다.
그렇기 때문에 다음과 같은 문제점 들을 겪게 되었다.
이것이 RESTful API 에서 데이터를 받아올 때 발생할 수 있는 현상이며 이를, Over-fetching 이라고 부른다.
N 개의 대상의 데이터를 받기 위해서는 N 번의 API 호출이 필요한 문제점
당신은 인스타그램을 클론코딩 하려고 한다.
수많은 기능 중에서도 당신은 개인피드 에서 기본기능을 담은 세 가지 화면을 보여주려고 한다.
2번과 3번을 위해서 각 mongooseSchema 에 새로운 항목을 넣고 DB 를 이전했다.
- userSchema
userSchema=mongoose.Schema({ following:[{type:mongoose.Schema.Types.ObjectId, ref:"User"}], followed:[{type:mongoose.Schema.Types.ObjectId, ref:"User"}] )};
- imageScheam
imageSchema=mongoose.Schema({ descirption:{type:String}, hahstags:{type:String}, });
Controller 를 만들기 전에,
각 화면에서 어떠한 모델의 어떤 정보가 필요한지 생각해보자.
개인피드
1.1. userModel
상세 이미지
2.1. userModel
2.2. imageModel
팔로잉, 팔로우 확인
3.1. userModel
이제 각 부분의 controller를 만들어보자
import userModel from "../model/userModel";
import imageModel from "../model/imageModel";
export const feedGet=async(req,res)=>{
const { id:userId }=req.params;
const userDB=await userModel.findById({id}).populate("Image");
return (userDB) ?
res.render(".../view/template/userFeed",{ userDB } :
res.render(".../view/template/userFeed",{ userDB:null, error:"404" };
};
export const detailGet=async(req,res)=>{
const { id:imageId }=req.params;
const imageDB=await imageModel.findById({id}).populate("User");
return (imageDB) ?
res.render(".../view/template/imageDetail",{ imageDB } :
res.render(".../view/template/imageDetail",{ imageDB:null, error:"404" };
};
export const followListGet=async(req,res)=>{
const { id:userId }=req.params;
const userModel=await userModel.findById({id});
return (userModel) ?
res.render(".../view/template/followList",{ imageDB } :
res.render(".../view/template/followList",{ imageDB };
};
위 코드를 보면 알 수 있겠지만,
userModel 과 imageModel 데이터를 호출할 때 2줄의 코드를 쓰는 것이 아니라
populate 메서드(mongoose)를 이용해서 1줄의 코드로 호출한 것을 알 수 있다.
하지만,
morgan 같은 상태관리 모듈을 설치해서 API 호출 내역을 살펴보면..
여러 번의 API 호출 내역이 발생한 것을 알 수 있다.
GET /userModel/:id
GET /imageModel/:id
이렇듯
하나의 Controller(서비스, 페이지 등)를 표현하기 위해서
여러 번의 API 호출이 발생하게 되는 상황을 Under-fethcing 이라고 한다.
그렇다면 이러한 문제를 해결할 수 있는 방법에는 어떠한 것이 있을까?
가장 대표적인 해결 방법은 GraphQL이다.