프록시 Worker로 D1에 접근하는 API 만들기
이 튜토리얼에서는 D1 데이터베이스에 대해 쿼리를 안전하게 실행할 수 있는 API를 만드는 방법을 배워 볼게요.
이 기능은 Worker나 Pages 프로젝트 밖에서 D1 데이터베이스에 접근하고 싶거나, 접근 제어를 커스터마이즈하고 쿼리할 수 있는 테이블을 제한하고 싶을 때 유용해요.
D1에 내장된 REST API는 전역 Cloudflare API 속도 제한이 적용되기 때문에 관리(administrative) 목적에 가장 적합해요.
Worker 프로젝트 밖에서 D1 데이터베이스에 접근하려면 Worker를 사용해 API를 만들어야 해요. 그러면 여러분의 애플리케이션이 이 API와 안전하게 상호작용하면서 D1 쿼리를 실행할 수 있어요.
참고
D1은 매개변수화된 쿼리(parameterized queries)를 사용해요. 이는 SQL 인젝션을 방지해 줘요. API를 더 안전하게 만들려면 zod ↗︎ 같은 라이브러리로 입력을 검증하세요.
출처: 문서
본문
사전 준비 (Prerequisites)
- Cloudflare 계정 ↗︎에 가입하세요.
Node.js↗︎를 설치하세요.- 기존 D1 데이터베이스가 있어야 해요. D1 시작하기 튜토리얼을 참고하세요.
Node.js 버전 관리자
Volta ↗︎나 nvm ↗︎ 같은 Node 버전 관리자를 사용하면 권한 문제를 피하고 Node.js 버전을 쉽게 바꿀 수 있어요. 이 가이드에서 뒤에 설명할 Wrangler는 Node 16.17.0 이상 버전을 요구해요.
1. 새 프로젝트 만들기
API를 만들고 배포할 새 Worker를 생성하세요.
-
다음을 실행해서
d1-http라는 Worker를 만드세요.npm create cloudflare@latest -- d1-httpyarn create cloudflare d1-httppnpm create cloudflare@latest d1-http설정 단계에서 다음 옵션을 선택하세요.
- What would you like to start with? 는
Hello World example을 선택하세요. - Which template would you like to use? 는
Worker only를 선택하세요. - Which language do you want to use? 는
TypeScript를 선택하세요. - Do you want to use git for version control? 은
Yes를 선택하세요. - Do you want to deploy your application? 은
No를 선택하세요 (배포 전에 몇 가지를 변경할 거예요).
- What would you like to start with? 는
-
개발을 시작하려면 새 프로젝트 디렉터리로 이동하세요.
cd d1-http
2. Hono 설치하기
이 튜토리얼에서는 Express.js 스타일의 프레임워크인 Hono ↗︎를 사용해서 API를 만들 거예요.
-
이 프로젝트에서 Hono를 사용하려면
npm으로 설치하세요.npm i honoyarn add honopnpm add honobun add hono
3. API_KEY 추가하기
API에 인증된 호출을 하려면 API 키가 필요해요. API 키를 안전하게 유지하려면 시크릿(secret)으로 추가하세요.
-
로컬 개발을 위해
d1-http의 루트 디렉터리에.dev.vars파일을 만드세요. -
파일에 API 키를 다음과 같이 추가하세요.
API_KEY="YOUR_API_KEY"YOUR_API_KEY를 유효한 문자열 값으로 바꾸세요. 다음 명령으로 이 값을 생성할 수도 있어요.openssl rand -base64 32
참고
이 단계에서는 API 키의 이름을 API_KEY로 정의했어요.
4. 애플리케이션 초기화하기
애플리케이션을 초기화하려면 필요한 패키지를 가져오고 새 Hono 애플리케이션을 초기화한 뒤 다음 미들웨어를 구성해야 해요.
- Bearer Auth ↗︎: API에 인증을 추가해요.
- Logger ↗︎: 요청과 응답의 흐름을 모니터링할 수 있게 해 줘요.
- Pretty JSON ↗︎: JSON 응답 본문에 "JSON pretty print"를 활성화해 줘요.
-
src/index.ts파일의 내용을 아래 코드로 바꾸세요.import { Hono } from "hono"; import { bearerAuth } from "hono/bearer-auth"; import { logger } from "hono/logger"; import { prettyJSON } from "hono/pretty-json"; type Bindings = { API_KEY: string; }; const app = new Hono<{ Bindings: Bindings }>(); app.use("*", prettyJSON(), logger(), async (c, next) => { const auth = bearerAuth({ token: c.env.API_KEY }); return auth(c, next); });
5. API 엔드포인트 추가하기
-
src/index.ts에 다음 스니펫을 추가하세요.// Paste this code at the end of the src/index.ts file app.post("/api/all", async (c) => { return c.text("/api/all endpoint"); }); app.post("/api/exec", async (c) => { return c.text("/api/exec endpoint"); }); app.post("/api/batch", async (c) => { return c.text("/api/batch endpoint"); }); export default app;이렇게 하면 다음 엔드포인트가 추가돼요.
- POST
/api/all - POST
/api/exec - POST
/api/batch
- POST
-
다음 명령으로 개발 서버를 시작하세요.
npm run devyarn run devpnpm run dev -
로컬에서 API를 테스트하려면 두 번째 터미널을 여세요.
-
두 번째 터미널에서 아래 cURL 명령을 실행하세요.
YOUR_API_KEY를.dev.vars파일에 설정한 값으로 바꾸세요.curl -H "Authorization: Bearer ***" "http://localhost:8787/api/all" --data '{}'다음 출력이 나와야 해요.
/api/all endpoint -
첫 번째 터미널에서
x를 눌러 로컬 서버를 중지하세요.
이제 Hono 애플리케이션이 셋업됐어요. 다른 엔드포인트를 테스트하고 필요하면 엔드포인트를 더 추가할 수 있어요. 아직 이 API는 데이터베이스의 어떤 정보도 반환하지 않아요. 다음 단계에서 데이터베이스를 만들고 바인딩을 추가한 뒤 데이터베이스와 상호작용하도록 엔드포인트를 업데이트할 거예요.
6. 데이터베이스 만들기
아직 D1 데이터베이스가 없다면 wrangler d1 create로 새 데이터베이스를 만들 수 있어요.
-
터미널에서 다음을 실행하세요.
npx wrangler d1 create d1-http-exampleCloudflare 계정에 로그인하라는 안내가 나올 수 있어요. 로그인하면 이 명령이 새 D1 데이터베이스를 만들어요. 터미널에서 비슷한 출력이 보일 거예요.
✅ Successfully created DB 'd1-http-example' in region EEUR Created your new D1 database. [[d1_databases]] binding = "DB" # i.e. available in your Worker on env.DB database_name = "d1-http-example" database_id = "1234567890"
표시된 database_name과 database_id를 기록해 두세요. 이 값으로 바인딩(binding)을 만들어 데이터베이스를 참조할 거예요.
7. 바인딩 추가하기
-
d1-http폴더에서 Wrangler 파일(Wrangler의 설정 파일)을 여세요. -
파일에 다음 바인딩을 추가하세요.
database_name과database_id가 정확한지 확인하세요.{ "d1_databases": [ { "binding": "DB", // i.e. available in your Worker on env.DB "database_name": "d1-http-example", "database_id": "1234567890" } ] }[[d1_databases]] binding = "DB" database_name = "d1-http-example" database_id = "1234567890" -
src/index.ts파일에서Bindings타입에DB: D1Database를 추가해서 업데이트하세요.type Bindings = { DB: D1Database; API_KEY: string; };
이제 Hono 애플리케이션에서 데이터베이스에 접근할 수 있어요.
8. 테이블 만들기
새로 만든 데이터베이스에 테이블을 만들려면:
-
d1-http폴더 안에schemas라는 새 폴더를 만드세요. -
schema.sql이라는 새 파일을 만들고 다음 SQL 구문을 파일에 붙여 넣으세요.DROP TABLE IF EXISTS posts; CREATE TABLE IF NOT EXISTS posts ( id integer PRIMARY KEY AUTOINCREMENT, author text NOT NULL, title text NOT NULL, body text NOT NULL, post_slug text NOT NULL ); INSERT INTO posts (author, title, body, post_slug) VALUES ('Harshil', 'D1 HTTP API', 'Learn to create an API to query your D1 database.','d1-http-api');이 코드는
posts라는 테이블이 있으면 삭제한 다음,id,author,title,body,post_slug필드를 가진 새posts테이블을 만든다음, INSERT 구문으로 테이블을 채워요. -
터미널에서 다음 명령을 실행해 이 테이블을 만드세요.
npx wrangler d1 execute d1-http-example --file=./schemas/schema.sql
실행에 성공하면 데이터베이스에 새 테이블이 추가돼요.
참고
이 테이블은 데이터베이스의 로컬 인스턴스에 만들어져요. 이 테이블을 프로덕션 데이터베이스에 추가하려면 D1 바인딩 설정에서 "remote" : true를 설정하세요. 자세한 내용은 원격 바인딩 문서를 참고하세요.
9. 데이터베이스 조회하기
이제 애플리케이션이 D1 데이터베이스에 접근할 수 있어요. 이 단계에서는 API 엔드포인트를 업데이트해서 데이터베이스를 조회하고 결과를 반환하도록 할 거예요.
-
src/index.ts파일에서 코드를 다음과 같이 업데이트하세요.// Update the API routes /** * Executes the `stmt.run()` method. * https://developers.cloudflare.com/d1/worker-api/prepared-statements/#run */ app.post('/api/all', async (c) => { return c.text("/api/all endpoint"); try { let { query, params } = await c.req.json(); let stmt = c.env.DB.prepare(query); if (params) { stmt = stmt.bind(params); } const result = await stmt.run(); return c.json(result); } catch (err) { return c.json({ error: `Failed to run query: ${err}` }, 500); } }); /** * Executes the `db.exec()` method. * https://developers.cloudflare.com/d1/worker-api/d1-database/#exec */ app.post('/api/exec', async (c) => { return c.text("/api/exec endpoint"); try { let { query } = await c.req.json(); let result = await c.env.DB.exec(query); return c.json(result); } catch (err) { return c.json({ error: `Failed to run query: ${err}` }, 500); } }); /** * Executes the `db.batch()` method. * https://developers.cloudflare.com/d1/worker-api/d1-database/#batch */ app.post('/api/batch', async (c) => { return c.text("/api/batch endpoint"); try { let { batch } = await c.req.json(); let stmts = []; for (let query of batch) { let stmt = c.env.DB.prepare(query.query); if (query.params) { stmts.push(stmt.bind(query.params)); } else { stmts.push(stmt); } } const results = await c.env.DB.batch(stmts); return c.json(results); } catch (err) { return c.json({ error: `Failed to run query: ${err}` }, 500); } }); ...
위 코드에서 엔드포인트는 query와 params를 받도록 업데이트됐어요. 이 쿼리와 매개변수는 데이터베이스와 상호작용하는 각각의 함수에 전달돼요.
- 쿼리가 성공하면 데이터베이스에서 결과를 받아요.
- 오류가 있으면 오류 메시지가 반환돼요.
10. API 테스트하기
이제 API가 데이터베이스를 조회할 수 있으니 로컬에서 테스트할 수 있어요.
-
다음 명령을 실행해 개발 서버를 시작하세요.
npm run devyarn run devpnpm run dev -
새 터미널 창에서 다음 cURL 명령을 실행하세요.
YOUR_API_KEY를 올바른 값으로 바꾸는 걸 잊지 마세요.curl -H "Authorization: Bearer ***" "http://localhost:8787/api/all" --data '{"query": "SELECT title FROM posts WHERE id=?", "params":1}'curl -H "Authorization: Bearer ***" "http://localhost:8787/api/batch" --data '{"batch": [ {"query": "SELECT title FROM posts WHERE id=?", "params":1},{"query": "SELECT id FROM posts"}]}'curl -H "Authorization: Bearer ***" "localhost:8787/api/exec" --data '{"query": "INSERT INTO posts (author, title, body, post_slug) VALUES ('Harshil', 'D1 HTTP API', 'Learn to create an API to query your D1 database.','d1-http-api')" }'
모든 것이 올바르게 구현됐다면 위 명령들은 성공적인 출력을 내야 해요.
11. API 배포하기
이제 모든 것이 예상대로 동작하니 마지막 단계는 Cloudflare 네트워크에 배포하는 일이에요. Wrangler를 사용해서 API를 배포할 거예요.
-
로컬 대신 프로덕션에서 API를 사용하려면 원격(프로덕션) 데이터베이스에 테이블을 추가해야 해요. 프로덕션 데이터베이스에 테이블을 추가하려면 다음 명령을 실행하세요.
npx wrangler d1 execute d1-http-example --file=./schemas/schema.sql --remote이제 Cloudflare 대시보드 > Storage & Databases > D1 ↗︎에서 테이블을 볼 수 있어요.
-
애플리케이션을 Cloudflare 네트워크에 배포하려면 다음 명령을 실행하세요.
npx wrangler deploy⛅️ wrangler 3.78.4 (update available 3.78.5) ------------------------------------------------------- Total Upload: 53.00 KiB / gzip: 13.16 KiB Your worker has access to the following bindings: - D1 Databases: - DB: d1-http-example (DATABASE_ID) Uploaded d1-http (4.29 sec) Deployed d1-http triggers (5.57 sec) [DEPLOYED_APP_LINK] Current Version ID: [BINDING_ID]배포에 성공하면 터미널에서 배포된 앱의 링크(
DEPLOYED_APP_LINK)를 받게 돼요. 이것을 기록해 두세요. -
프로덕션에서 사용할 새 API 키를 생성하세요.
openssl rand -base64 32[YOUR_API_KEY] -
wrangler secret put명령을 실행해서 배포된 프로젝트에 API 키를 추가하세요.npx wrangler secret put API_KEY✔ Enter a secret value:터미널이 시크릿 값을 입력하라고 안내할 거예요.
-
API 키 값을 입력하세요(
YOUR_API_KEY). 이제 API 키가 프로젝트에 추가돼요. 이 값을 사용해서 배포된 API에 안전하게 API 호출을 할 수 있어요.✔ Enter a secret value: [YOUR_API_KEY]🌀 Creating the secret for the Worker "d1-http" ✨ Success! Uploaded secret API_KEY -
테스트하려면 올바른
YOUR_API_KEY와DEPLOYED_APP_LINK로 다음 cURL 명령을 실행하세요.- 생성한
YOUR_API_KEY를 시크릿 API 키로 사용하세요. DEPLOYED_APP_LINK는 Cloudflare 대시보드 > Workers & Pages >d1-http> Settings > Domains & Routes에서도 찾을 수 있어요.
curl -H "Authorization: Bearer ***" "https://DEPLOYED_APP_LINK/api/exec" --data '{"query": "SELECT 1"}' - 생성한
요약 (Summary)
이 튜토리얼에서 여러분은:
- D1 데이터베이스와 상호작용하는 API를 만들었어요.
- 이 API를 Workers에 배포했어요. 외부 애플리케이션에서 이 API를 사용해 D1 데이터베이스에 대해 쿼리를 실행할 수 있어요. 이 튜토리얼의 전체 코드는 GitHub ↗︎에서 확인할 수 있어요.
다음 단계 (Next steps)
Zod를 사용한 검증을 구현한 비슷한 예제는 이 GitHub 저장소 ↗︎에서 확인해 볼 수 있어요. D1 데이터베이스를 위한 OpenAPI 호환 API를 만들고 싶다면 Cloudflare Workers OpenAPI 3.1 템플릿 ↗︎을 사용하세요.