예전에 노션 클론 코딩을 하고 회고 글을 작성했었습니다
미뤄놨던 배포와 버그 수정, 리팩토링을 진행할 예정입니다
그 중 배포할 때 api 요청 url과 관련 api key에 대해서 숨겨야 하는 사항이 있어서 vercel의 serverless function을 먼저 도입하게 되었습니다
이대로 배포하면 안되니깐...
이 글은 vercel serverless를 사용하는 예제 글입니다
Vercel Serverless Funtion은 사용자 인증, 양식 제출, DB query 등의 명령을 추가 인프라 없이 vercel에서 자체적으로 처리하도록 합니다
이 때 네트워크 요청이 감춰집니다
api url과 key를 숨겨야 하니 적용해야 합니다
Vercel Serverless Funtion에 있는 적용 방법을 간략하게 번역한 내용입니다
프로젝트의 루트 디렉토리에 api
폴더를 만들고, 이 폴더 안에서 서버리스 함수를 작성합니다
결과적으로 api
폴더가 /api
url로 매핑됩니다
serverless 함수에서 환경 변수를 설정할 수 있습니다
.env 파일을 이용합니다
url에 입력되는 값을 동적으로 받고 싶다면 파일명을 중괄호로 감싸줍니다
ex) [name].js
npx create-react-app folder-name
으로 리액트 프로젝트를 하나 만듭니다
//App.js
import './App.css';
import { useEffect, useState } from 'react';
function App() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos')
.then((response) => response.json())
.then((result) => setData(result));
}, []);
useEffect(() => {
console.log(data);
}, [data]);
return (
<ol>
{data.map(({ id, title }) => (
<li key={id}>{title}</li>
))}
</ol>
);
}
export default App;
App.js를 위 코드처럼 작성하고 npm start
명령어를 입력합니다
당연하게도 jsonplaceholder로 요청을 보낸 기록이 남습니다
이제 serverless 함수를 도입하겠습니다
// /api/index.js
import fetch from 'node-fetch';
export default async function handler(request, response) {
const res = await fetch('https://jsonplaceholder.typicode.com/todos');
const data = await res.json();
return response.status(200).json({ data });
}
루트 디렉토리에 api폴더를 만들고, api 폴더에 index.js
를 위 코드처럼 만듭니다
이 때 node-fetch는 2버전으로 설치합니다
그리고 레포지토리를 vercel에서 배포합니다
배포 링크에 /api
을 붙이면 /api/index.js
를 통해 얻은 data를 볼 수 있습니다
jsonplaceholder로 요청을 보냈다는 기록은 Network 탭에서 찾을 수 없습니다
하지만 레포지토리를 들어와서 코드를 보면 요청 보낸 곳을 알 수 있기 때문에 환경 변수를 설정하겠습니다
먼저 vercel settings - Environment Variables에서 위처럼 설정합니다
// /api/index.js
import fetch from 'node-fetch';
export default async function handler(request, response) {
const res = await fetch(process.env.BASE_URL);
const data = await res.json();
return response.status(200).json({ data });
}
api 폴더의 index.js를 위와 같이 수정합니다
jsonplaceholder로 요청보내던 내용을 환경변수의 BASE_URL로 요청을 보내도록 수정했습니다
// App.js
import './App.css';
import { useEffect, useState } from 'react';
function App() {
const [loaded, setLoaded] = useState(false);
const [data, setData] = useState([]);
useEffect(() => {
fetch('/api')
.then((response) => response.json())
.then((json) => {
setData(json.data);
setLoaded(true);
});
}, []);
useEffect(() => {
console.log(data);
}, [data]);
return loaded ? (
<ol>
{data.map(({ id, title }) => (
<li key={id}>{title}</li>
))}
</ol>
) : (
'데이터 fetch 미완료'
);
}
export default App;
App.js를 위 코드처럼 수정합니다
/api url로 요청을 보내고, 받은 데이터의 .data를 사용하도록 했습니다
// /api/[page].js
import fetch from 'node-fetch';
export default async function handler(request, response) {
const { page } = request.query;
const res = await fetch(`${process.env.BASE_URL}/${page}`);
const data = await res.json();
return response.status(200).json({ data });
}
api 폴더 안에 index.js가 이미 있는 상황에서
[page].js를 위 코드처럼 만들어줍니다
/api/1
/api/2
같은 url로 접속하면 그 값을 request.query에서 page라는 이름으로 데이터를 받게 됩니다
그 page에 해당하는 jsonplaceholder 요청 결과를 반환하는 serverless 함수가 만들어졌습니다
물론 network에는 jsonplaceholder를 찾아볼 수 없습니다
github 링크에서 코드를 볼 수 있고
vercel 배포 링크에서 위 예제를 테스트할 수 있습니다
메인은 새로고침 시 /api로 요청을 보내고 렌더링합니다
/api는 process.env.BASE_URL로 정의된 jsonplaceholder 전체 값을 가져옵니다
/api/1은 /api와 동일하지만 해당 값만을 가져옵니다
노션 클론코딩에도 serverless 빨리 도입해서 리팩토링해야징~
참고