본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

프록시 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)

  1. Cloudflare 계정 ↗︎에 가입하세요.
  2. Node.js ↗︎를 설치하세요.
  3. 기존 D1 데이터베이스가 있어야 해요. D1 시작하기 튜토리얼을 참고하세요.

Node.js 버전 관리자

Volta ↗︎나 nvm ↗︎ 같은 Node 버전 관리자를 사용하면 권한 문제를 피하고 Node.js 버전을 쉽게 바꿀 수 있어요. 이 가이드에서 뒤에 설명할 Wrangler는 Node 16.17.0 이상 버전을 요구해요.

1. 새 프로젝트 만들기

API를 만들고 배포할 새 Worker를 생성하세요.

  1. 다음을 실행해서 d1-http라는 Worker를 만드세요.

    npm create cloudflare@latest -- d1-http
    
    yarn create cloudflare d1-http
    
    pnpm 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를 선택하세요 (배포 전에 몇 가지를 변경할 거예요).
  2. 개발을 시작하려면 새 프로젝트 디렉터리로 이동하세요.

    cd d1-http
    

2. Hono 설치하기

이 튜토리얼에서는 Express.js 스타일의 프레임워크인 Hono ↗︎를 사용해서 API를 만들 거예요.

  1. 이 프로젝트에서 Hono를 사용하려면 npm으로 설치하세요.

    npm i hono
    
    yarn add hono
    
    pnpm add hono
    
    bun add hono
    

3. API_KEY 추가하기

API에 인증된 호출을 하려면 API 키가 필요해요. API 키를 안전하게 유지하려면 시크릿(secret)으로 추가하세요.

  1. 로컬 개발을 위해 d1-http의 루트 디렉터리에 .dev.vars 파일을 만드세요.

  2. 파일에 API 키를 다음과 같이 추가하세요.

    API_KEY="YOUR_API_KEY"
    

    YOUR_API_KEY를 유효한 문자열 값으로 바꾸세요. 다음 명령으로 이 값을 생성할 수도 있어요.

    openssl rand -base64 32
    

참고

이 단계에서는 API 키의 이름을 API_KEY로 정의했어요.

4. 애플리케이션 초기화하기

애플리케이션을 초기화하려면 필요한 패키지를 가져오고 새 Hono 애플리케이션을 초기화한 뒤 다음 미들웨어를 구성해야 해요.

  1. 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 엔드포인트 추가하기

  1. 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
  2. 다음 명령으로 개발 서버를 시작하세요.

    npm run dev
    
    yarn run dev
    
    pnpm run dev
    
  3. 로컬에서 API를 테스트하려면 두 번째 터미널을 여세요.

  4. 두 번째 터미널에서 아래 cURL 명령을 실행하세요. YOUR_API_KEY를 .dev.vars 파일에 설정한 값으로 바꾸세요.

    curl -H "Authorization: Bearer ***" "http://localhost:8787/api/all" --data '{}'
    

    다음 출력이 나와야 해요.

    /api/all endpoint
    
  5. 첫 번째 터미널에서 x를 눌러 로컬 서버를 중지하세요.

이제 Hono 애플리케이션이 셋업됐어요. 다른 엔드포인트를 테스트하고 필요하면 엔드포인트를 더 추가할 수 있어요. 아직 이 API는 데이터베이스의 어떤 정보도 반환하지 않아요. 다음 단계에서 데이터베이스를 만들고 바인딩을 추가한 뒤 데이터베이스와 상호작용하도록 엔드포인트를 업데이트할 거예요.

6. 데이터베이스 만들기

아직 D1 데이터베이스가 없다면 wrangler d1 create로 새 데이터베이스를 만들 수 있어요.

  1. 터미널에서 다음을 실행하세요.

    npx wrangler d1 create d1-http-example
    

    Cloudflare 계정에 로그인하라는 안내가 나올 수 있어요. 로그인하면 이 명령이 새 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. 바인딩 추가하기

  1. d1-http 폴더에서 Wrangler 파일(Wrangler의 설정 파일)을 여세요.

  2. 파일에 다음 바인딩을 추가하세요. 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"
    
  3. src/index.ts 파일에서 Bindings 타입에 DB: D1Database를 추가해서 업데이트하세요.

    type Bindings = {
    	DB: D1Database;
    	API_KEY: string;
    };
    

이제 Hono 애플리케이션에서 데이터베이스에 접근할 수 있어요.

8. 테이블 만들기

새로 만든 데이터베이스에 테이블을 만들려면:

  1. d1-http 폴더 안에 schemas라는 새 폴더를 만드세요.

  2. 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 구문으로 테이블을 채워요.

  3. 터미널에서 다음 명령을 실행해 이 테이블을 만드세요.

    npx wrangler d1 execute d1-http-example --file=./schemas/schema.sql
    

실행에 성공하면 데이터베이스에 새 테이블이 추가돼요.

참고

이 테이블은 데이터베이스의 로컬 인스턴스에 만들어져요. 이 테이블을 프로덕션 데이터베이스에 추가하려면 D1 바인딩 설정에서 "remote" : true를 설정하세요. 자세한 내용은 원격 바인딩 문서를 참고하세요.

9. 데이터베이스 조회하기

이제 애플리케이션이 D1 데이터베이스에 접근할 수 있어요. 이 단계에서는 API 엔드포인트를 업데이트해서 데이터베이스를 조회하고 결과를 반환하도록 할 거예요.

  1. 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가 데이터베이스를 조회할 수 있으니 로컬에서 테스트할 수 있어요.

  1. 다음 명령을 실행해 개발 서버를 시작하세요.

    npm run dev
    
    yarn run dev
    
    pnpm run dev
    
  2. 새 터미널 창에서 다음 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를 배포할 거예요.

  1. 로컬 대신 프로덕션에서 API를 사용하려면 원격(프로덕션) 데이터베이스에 테이블을 추가해야 해요. 프로덕션 데이터베이스에 테이블을 추가하려면 다음 명령을 실행하세요.

    npx wrangler d1 execute d1-http-example --file=./schemas/schema.sql --remote
    

    이제 Cloudflare 대시보드 > Storage & Databases > D1 ↗︎에서 테이블을 볼 수 있어요.

  2. 애플리케이션을 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)를 받게 돼요. 이것을 기록해 두세요.

  3. 프로덕션에서 사용할 새 API 키를 생성하세요.

    openssl rand -base64 32
    
    [YOUR_API_KEY]
    
  4. wrangler secret put 명령을 실행해서 배포된 프로젝트에 API 키를 추가하세요.

    npx wrangler secret put API_KEY
    
    ✔ Enter a secret value:
    

    터미널이 시크릿 값을 입력하라고 안내할 거예요.

  5. 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
    
  6. 테스트하려면 올바른 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)

이 튜토리얼에서 여러분은:

  1. D1 데이터베이스와 상호작용하는 API를 만들었어요.
  2. 이 API를 Workers에 배포했어요. 외부 애플리케이션에서 이 API를 사용해 D1 데이터베이스에 대해 쿼리를 실행할 수 있어요. 이 튜토리얼의 전체 코드는 GitHub ↗︎에서 확인할 수 있어요.

다음 단계 (Next steps)

Zod를 사용한 검증을 구현한 비슷한 예제는 이 GitHub 저장소 ↗︎에서 확인해 볼 수 있어요. D1 데이터베이스를 위한 OpenAPI 호환 API를 만들고 싶다면 Cloudflare Workers OpenAPI 3.1 템플릿 ↗︎을 사용하세요.

더 알아보기 (Learn more)