위 링크의 가이드를 보고 따라해봤습니다.
Cloudflare 작업자와 Fauna를 사용하는 이유는?
faunaDB는 HTTP 기반의 연결 모델 덕분에 workers와 원활하게 통합될 수 있다. 두 서비스 모두 사용하는 애플리케이션은 서버리스 엔드 투 엔드로 실행할 수 있으며 인프라를 관리할 필요없이 무한히 확장할 수 있다.
일반적으로 서버는 단일 위치에서 로직과 데이터베이스 쿼리를 실행한다. Worker + Fauna를 사용하면 데이터와 코드가 여러 위치에서 실행되고 왕복 읽기 대기 시간을 크게 줄일 수 있다.
만들 것
간단한 제품 인벤토리를 관리하는 CRUD 기능이 있는 js REST API
{
title: string,
serialNumber: string,
weightLabs: float,
quantity: int
}
위 형식의 데이터가 포함된다.
Fauna의 컬렉션은 단순한 도큐먼트 버킷이다.
요구사항
- Node
- Cloudflare wrangler CLI
Fauna 설정
디비 생성
먼저 Fauna 대쉬보드에 접속하여 새 데이터베이스를 생성합니다.
컬렉션 생성
다음 인벤토리에 대한 문서를 저장할 프로덕트 컬렉션을 생성합니다.
CreateCollection({ name: "Products" })
위의 FQL 쿼리로 컬렉션을 생성했습니다. 옆의 Collections 탭에서 GUI 로 생성할 수도 있습니다.
CreateCollection({ name: "Products" })
{
ref: Collection("Products"),
ts: 1643977115450000,
history_days: 30,
name: "Products"
}
>> Time elapsed: 154ms
FQL 실행 후 위의 리턴값을 얻었는데요, 각각 데이터의 정보는 아래와 같습니다.
ref - 컬렉션 자체에 대한 참조
ts - 생성 타임스탬프
history-days - Fuana가 컬렉션 문서의 변경 사항을 유지하는 기간을 결정
name - 컬렉션 이름
서버 키 생성
대쉬보드의 좌측 보안탭에서 생성할 수 있습니다.
Worker 설정
설치
npm i @cloudflare/wrangler -g
wrangler login
wrangler 설치 후 cloudflare 계정 로그인을 합니다.
wrangler 설정
wrangler generate fauna-workers
위 명령어로 workers 프로젝트를 생성합니다.
wrangler.toml
name = "fauna-workers"
type = "javascript"
account_id = ""
workers_dev = true
route = ""
zone_id = ""
compatibility_date = "2022-02-04"
그후 toml 파일에 정보를 기입합니다.
wrangler publish
이상태에서 위 명령어를 실행하면 hello worker 페이지가 project-name.userId.workers.dev url에 배포됩니다. cloudflare 사이트의 worker 대쉬보드에도 설정한 프로젝트가 자동으로 생성됨을 볼 수 있습니다.
fauna 비밀키 등록
wrangler secret put FAUNA_SECRET
worker가 생성 및 배포되면 cloudflare의 인프라에 fauna 키를 안전하게 저장할 수 있습니다.
위 명령어를 실행한 후 이전에 얻은 fauna 서버 암호를 붙여 넣습니다.
wrangler.toml 에서 직접 환경 변수를 구성하는 것보다 더 안전한 방법인듯 하네요.
종속성 설치
yarn add faunadb
faunadb는 데이터베이스 드라이버이고, worktop은 worker를 더 편하게 사용할 수 있도록 하는 프레임워크입니다.
원글에서는 worktop 프레임워크를 사용하지만 아래 에러로 제외했습니다.
Error: The package "esbuild-darwin-64" could not be found, and is needed by esbuild.
js 유틸리티 함수
export function getFaunaError (error) {
const {code, description} = error.requestResult.responseContent.errors[0];
let status;
switch (code) {
case 'instance not found':
status = 404;
break;
case 'instance not unique':
status = 409;
break;
case 'permission denied':
status = 403;
break;
case 'unauthorized':
case 'authentication failed':
status = 401;
break;
default:
status = 500;
}
return {code, description, status};
}
fuana 에러처리용 유틸리티 함수를 utils.js 파일에 추가합니다.
product 생성 로직
index.js
import faunadb from 'faunadb'
import { Router } from 'itty-router'
import { getFaunaError } from './utils'
const router = Router()
const faunaClient = new faunadb.Client({
secret: FAUNA_SECRET,
})
const { Create, Collection } = faunadb.query
router.post('/products', async req => {
try {
const { serialNumber, title, weightLbs } = await req.json()
const result = await faunaClient.query(
Create(Collection('Products'), {
data: {
serialNumber,
title,
weightLbs,
quantity: 0,
},
}),
)
return new Response(
JSON.stringify({
productId: result.ref.id,
}),
)
} catch (error) {
const faunaError = getFaunaError(error)
return new Response(JSON.stringify(faunaError), {
status: faunaError.status,
})
}
})
router.get('/', () => new Response('hello'))
addEventListener('fetch', event => {
event.respondWith(router.handle(event.request))
})
faunaClient 연결이 매우 간단하네요
생성된 product 확인
product 조회 로직 작성
router.get('/products/:productId', async req => {
try {
const { productId } = req.params
const result = await faunaClient.query(
Get(Ref(Collection('Products'), productId)),
)
return new Response(JSON.stringify(result))
} catch (error) {
console.log(error)
const faunaError = getFaunaError(error)
return new Response(JSON.stringify(faunaError), {
status: faunaError.status,
})
}
})
Get 조회 쿼리로 동일 productId의 문서를 찾습니다.
조회 성공 결과
const start = Date.now()
const result = await faunaClient.query(
Get(Ref(Collection('Products'), productId)),
)
const time = Date.now() - start
위 조회 로직에서 디비에 접근하기 전 후 타이머로 재보니 100~200ms 내외로 끝나네요.
서버리스 함수 전체로는 200~500ms 정도 걸립니다.
이정도면 나쁘지 않은 것 같습니다.
update, delete는 생략합니다.
단점
FQL 문법이 생소하다..
‣
Loading Comments...