Cloudflare Workers 與 D1 的巧妙結合

前言廢話

這正是個 Serverless 無伺服器當道的年代,不久前才剛考完 AWS 證照,裡面瘋狂地提及 AWS Lambda,不經讓我想起之前由 Cloudflare 推出的 Workers 與 D1。

D1 是一個由 Cloudflare 託管的 sqlite 資料庫,透過與 Cloudflare Workers 的結合,你可以巧妙的建造出一款無伺服器的小網站。適合做一些需要快速且小巧的專案,不過由於 Workers 每天是有配額限制的,所以可能還是不太能做太沉重的事情。

這篇文章會使用 hono 這款微型網站框架,配合 D1 並部屬到 Workers 上,簡單製作一個 API 伺服器。

安裝 Wrangler

Wrangler 是一款 Cloudflare 開發用於 Workers 的 cli 工具,我們使用 npm 在全域安裝他。

npm i @cloudflare/wrangler -g

安裝 hono

在你的電腦上建立一個資料夾,名字取名為 api,並執行以下 npm 命令。

npm install hono

在這裡面建立一個資料夾 src,並新建一個檔案名為 index.ts,內容如下:

import { Hono } from "hono";
 
const app = new Hono();
 
app.get("/getData", async (c) => {
  // Do your stuff here.
});

app.get("/getData/:name", async (c) => {
  // Do your stuff here.
});
 
app.post("/postData", async (c) => {
  // Do your stuff here.
});
 
export default app;

建立 D1 資料庫

接著,我們要在 D1 建立一個資料庫。我們使用 wrangler 中建立一個名為 api 的資料庫。(初次使用可能會要求登入 Cloudflare)

wrangler d1 create api

建立完後,你的終端機最下面會顯示此內容,我們將他記起來,待會會用到。

001.jpg

與資料庫互動

若要簡單與 SQL 互動,你可以直接透過這樣的指令:

wrangler d1 execute api --command "SELECT * FROM user"

不過我們的 SQL 中現在沒有任何資料,因此我們來製作一些吧!

新增一個資料夾 sql,並新增一個檔名為 command.sql 的檔案,內容如下:

CREATE TABLE IF NOT EXISTS user (
    id integer PRIMARY KEY AUTOINCREMENT,
    name text NOT NULL
);
 
INSERT INTO user(name) VALUES("cre0809");
INSERT INTO user(name) VALUES("test");

接著,我們可以使用 wrangler 的命令,讓他讀取這個檔案:

wrangler d1 execute api --file sql/command.sql

取得資料

回到 src/index.ts 這個檔案,我們來編輯一下 /getData 這個區塊。

app.get("/getData", async (c) => {
    const { results } = await c.env.DB.prepare(`SELECT * FROM user`).all();
    return c.json(results);
});

app.get("/getData/:name", async (c) => {
    const { name } = c.req.param();
    const { results } = await c.env.DB.prepare(
        `SELECT * FROM user WHERE name = ?`
    ).bind(name).all();
    return c.json(results);
});

如上面的程式碼,第一個是單純列出所有資料,第二格則是取得一個 param 的資料,並結合 WHERE 做查詢。

插入資料

一樣使用 src/index.ts 這個檔案,我們編輯 /postData 這個區塊。

app.post("/postData", async (c) => {
    const body = await c.req.parseBody();

    if (!body.name) {
        c.status(400);
        return c.json({ code: 400, status: "Bad Request", message: "Missing query parameter."});
    }
 
    const { success } = await c.env.DB.prepare(
        `INSERT INTO user(name) VALUES(?)`
    ).bind(body.name).run();
 
    if (success) {
        c.status(201);
        return c.json({ code: 201, status: "Created"});
    }
    else {
        c.status(500);
        return c.json({ code: 500, status: "Internal Server Error", message: "Something went wrong."});
    }
});

部屬應用程式

api 資料夾底下建立一個 wrangler.toml 的檔案,插入以下內容:

name = "api"
main = "src/index.ts"
compatibility_date = "2023-06-20"
 
[[ d1_databases ]]
binding = "DB"
database_name = "api"
database_id = "<YOUR_DATABASE_ID>"

還記得我們前面說要記下的資料嗎?我們在上方的文件中將他放入。

現在執行以下命令來部屬他!

wrangler deploy

在命令列最下方可以看到已經部屬的網址,接下來就來成果展示吧!

002.jpg

成果展示

我們使用 Postman 這款工具來驗證我們的簡單 API 應用程式。

首先是 /getData,我們可以看到所有結果都列了出來。

003.jpg

接著使用 /getData/cre0809,使用 WHERE 的方式列出指定資料。

004.jpg

接著使用 /postData,並使用 form-data 帶了一個名為 name 的資料過去。

005.jpg

最後,再列出所有一次,可以看到加進去的資料也出現了。

006.jpg

結語

我們就這樣打造了一款無伺服器的 API 介接應用程式,其實這個過程真的不難。Serverless 是個未來的趨勢,透過 Cloudflare 這樣免費的資源,可以多多利用!