아주 간단합니다. 백엔드 API서버를 하나 만든다고 생각하시면 될 것 같아요
// index.js
const jsonServer = require("json-server");
// 그들이 만들어 둔 auth server library
const auth = require("json-server-auth");
const app = jsonServer.create();
const router = jsonServer.router("db.json");
app.db = router.db;
app.use(auth);
app.use(router);
app.listen(process.env.PORT || 3000);
// db.json
{
"users": [
]
}
// package.json
{
"name": "json-auth-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1",
},
"author": "",
"license": "ISC",
"devDependencies": {
"json-server": "^0.17.0",
"json-server-auth": "^2.1.0"
}
}
터미널에서 node index.js
를 실행하면 백엔드 서버가 '로컬'에서 실행됩니다. 로컬에서 실행되는 경우 3000포트로 서버를 열어 놨으므로 localhost:3000
주소로 요청을 보내시면 됩니다.
아래 헤로쿠 문서만 보신다면 배포 할 수 있습니다 !!! 간단하죠잉 배포 따라히기! 그럼 저희는 총 두개의 백엔드 API 서버를 갖게되었어요. (로컬 백엔드 서버와 배포 백엔드 서버)
로컬 클라이언트 -> 로컬 백엔드 서버
배포 클라이언트 -> 배포 백엔드 서버로 요청이 가게끔해야겠죠? 그전에 cors
에러가 발생하게 될 테니 이를 해결해주고 위 작업을 해봅시다.
개발단, 배포단 모두 클라이언트와 API서버는 서로 다른 출처(개발단 : 포트가 다름, 배포단 : 주소 자체가 다름)이기 때문에 CORS 정책을 위반하여 에러가 발생하게 됩니다. 여기서 기억해야하는 사실은 CORS 정책은 브라우저 정책이기 때문에 서버간의 소통에선 서로 다른 출처여도 에러가 발생하지 않습니다. -> CORS란
서버간 소통에는 에러가 발생하지 않는다구?! 그럼 프록시 서버를 이용하면 개발단에서 CORS 에러를 해결할 수 있겠군요..?! (프록싱이 하기 싫다면..? API서버에서 모든 응답 헤더의 Access-Control-Allow-Origin
을 바꾸는 처리를 해주면 되겠군요..!)
1. 서버에서 cors 미드웨어를 사용하여 교차 출처를 허용하도록 한다.
이 방법은 배포단, 개발단에서의 모든 CORS에러를 해결해줍니다.
const jsonServer = require("json-server");
const auth = require("json-server-auth");
const cors = require("cors");
const app = jsonServer.create();
const router = jsonServer.router("db.json");
app.db = router.db;
app.use(
cors({
// 모든 클라이언트에서의 요청을 거부하지 않는다.
// origin: "*",
// 특정 클라이언트라면? 9000포트로 열린 클라이언트에서의 요청은 거부하지 않습니다.
origin: "http://localhost:9000"
credentials: true,
})
);
app.use(auth);
app.use(router);
app.listen(process.env.PORT || 3000);
2. 클라이언트 단에서의 요청을 프록싱 한다.
이 방법은 프로덕션에서는 사용할 수 없어요... devServer
에서의 옵션이기 때문에.. 프로덕션에서 사용하고자 한다면 프록시 서버를 개발하거나 서드파티 프록시 서버를 통해 우회하면 될 것 같아요!
devServer: {
port: 9000,
historyApiFallback: true,
// api
// localhost:3000으로 에서 보내는 요청으로 변경합니다.
proxy: {
'/api/*': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
},
},
},
이를 처리하는 방법은 간단합니다. production
일 때 사용하는 env
파일, development
일 때 사용하는 env
파일을 구분하여 관리하시면 됩니다.
클라이언트 프로젝트 폴더에 .env.production
- .env.development
를 생성합니다.
// .env.development
API_URL="로컬 백엔드 API주소"
// .env.production
API_URL="배포 백엔드 API주소"
이 둘을 웹팩에서 인식하게 하고 클라이언트로 주입해준다면 해결되겠죠?
webpack
-> 클라이언트 빌드 파일
로 주입하기
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const dotenv = require('dotenv');
module.exports = (env, options) => {
// production일때와 devlopment 일 때 사용하게 되는 env파일이 다르므로 이를 처리해야합니다.
// 이거 하나님이 해주는게 아니에요 스크립트에서 webpack 옵션으로 처리해야합니다.
dotenv.config({ path: `.env.${options.mode}` });
return {
mode: options.mode,
entry: './src/index.ts',
resolve: {
extensions: ['.js', '.css', '.ts'],
},
devServer: {
port: 9000,
historyApiFallback: true,
proxy: {
'/api/*': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
},
},
},
// ...
plugins: [
new webpack.DefinePlugin({
// 클라이언트에 전역변수로 주입합니다.
API_URL: JSON.stringify(process.env.API_URL),
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './index.html',
}),
new CopyPlugin({
patterns: [{ from: 'public', to: '' }],
}),
],
};
};
// package.json
"scripts":{
// --mode development 를 주게되면 웹팩 설정 파일에서 options.mode로 조회할 수 있습니다.
"start": "webpack serve --open --mode development",
"build": "webpack --mode production",
}
사용처에선 다음과 같이 전역 변수처럼 사용할 수 있어요
export const fetcher = async ({ path, option }) => {
// 전역변수처럼 사용한다.
const response = await fetch(`${API_URL}${path}`, option);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`api 요청 중 에러 발생: ${API_ERROR_MSG[errorText]}`);
}
const data = await response.json();
return data;
};