Open8
Rust , Headless CMS作成メモ Workers-rs

概要
- Rust , Headless CMS試作メモになります。
- cloudflare Workers-rs で、実装
- データは、 D1 database 保存
- 管理画面は、 React フルスタック
- APIは、ほぼ 100% Rust言語
- 小規模アプリ等などの、バックエンドにしたい。
- フロントは 生成AI, バックは Headless CMS使用で、時短できれば
[ 公開 2025/09/04 ]
環境
- cloudflare Workers-rs
- D1 database
- rustc 1.88.0 , cargo 1.88.0
- node 22
書いたコード
- dev-start
npm run build
npm run dev
設定方法
- headless-2025/wrangler.toml
- db 接続設定
- API_KEY認証の、KEYを決める
- 管理画面ログイン: USER_NAME , PASSWORD
[vars]
USER_NAME = "user1@example.com"
PASSWORD = "1234"
API_KEY = "123"
API使い方
- 例: List
- node.js
- your-key: API_KEY , wrangler.toml に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const response = await fetch("http://localhost:8787/api/data/list?content=todo", {
method: 'GET',
headers: {
'Authorization': 'your-key',
}
});
if (!response.ok) {
const text = await response.text();
console.log(text)
throw new Error('Failed to item');
}
const json = await response.json();
console.log(json)
}catch(e){console.log(e)}
}
start();
-
Create
-
your-key: API_KEY , wrangler.toml に設定した API_KEY
-
content: データ種類
-
data: json データ
const start = async function() {
try{
const item = {
content: "test1",
data: JSON.stringify({
"title": "tit-1",
"body": "body-1",
})
}
const response = await fetch("http://localhost:8787/api/data/create", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'your-key',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
}
return response.json();
}catch(e){console.log(e)}
}
start();

Rust Axum , Headless CMSの例
- Axum使用、Headless CMS作成メモになります。
- 今回は、サバーレスではなく。セルフホスト等でデプロイ想定です。
環境
- Axum
- SQLite database
- rustc 1.88.0 , cargo 1.88.0
- node 20
- react
書いたコード
- dev-start
npm run build
npm run dev
設定方法
- .env
- API_KEY認証の、KEYを決める
- 管理画面ログイン: USER_NAME , PASSWORD
API_KEY=123
USER_NAME = "user1@example.com"
PASSWORD = "1234"
- table
CREATE TABLE IF NOT EXISTS hcm_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
data TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
- sqlite3で、 db作成
- Dbname: cms.db
sqlite3 cms.db
API使い方
- 例: List
- node.js
- your-key: API_KEY , .env に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const response = await fetch("http://localhost:3000/api/data/list?content=test1", {
method: 'GET',
headers: {
'Authorization': 'your-key',
}
});
if (!response.ok) {
const text = await response.text();
console.log(text)
throw new Error('Failed to create item');
}
const json = await response.json();
console.log(json)
}catch(e){console.log(e)}
}
start();
-
Create
-
your-key: API_KEY , .env に設定した API_KEY
-
content: データ種類
-
data: json データ
const start = async function() {
try{
const item = {
content: "test2",
data: JSON.stringify({
"title": "tit-22",
"body": "body-22",
})
}
const response = await fetch("http://localhost:3000/api/data/create", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'your-key',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
}
return response.json();
}catch(e){console.log(e)}
}
start();

PGLite WASM + Bun , Headless CMSの例
- PGLite WASM、Headless CMS作成メモになります。
- 今回は、サバーレスではなく。セルフホスト等でデプロイ想定です。
関連
- 前のPGLite 記事 インストールなど
環境
- PGLite WASM , popstgres 17.x
- bun 1.2.20
- react
書いたコード
- db create
bun run db_init.ts
- dev-start
npm run build
npm run dev
設定方法
- .env
- DATA_DIR: PGLite data folder
- API_KEY認証の、KEYを決める
- 管理画面ログイン: USER_NAME , PASSWORD
DATA_DIR="/path/cmsdata"
API_KEY=1234
USER_NAME = "user1@example.com"
PASSWORD = "123"
API使い方
- 例: List
- node.js
- your-key: API_KEY , .env に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const response = await fetch("http://localhost:3000/api/data/list?content=test1", {
method: 'GET',
headers: {
'Authorization': 'your-key',
}
});
if (!response.ok) {
const text = await response.text();
console.log(text)
throw new Error('Failed to item');
}
const json = await response.json();
console.log(json)
}catch(e){console.log(e)}
}
start();
-
Create
-
your-key: API_KEY , .env に設定した API_KEY
-
content: データ種類
-
data: json データ
const start = async function() {
try{
const item = {
content: "test2",
data: JSON.stringify({
"title": "tit-22",
"body": "body-22",
})
}
const response = await fetch("http://localhost:3000/api/data/create", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'your-key',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
}
return response.json();
}catch(e){console.log(e)}
}
start();

Headless CMS , 接続アプリの例
- Headless CMS API使用して、連携アプリ作成
- bun + Reactで作成。
環境
- bun 1.2.20
- React
書いたコード
- .env
- EXTERNAL_API_URL: 接続API URRL
- API_KEY: Headless CMS に設定した API_KEY
EXTERNAL_API_URL="http://localhost:8787"
API_KEY=123
- dev-start
npm run build
npm run dev
- 一覧
- headless-app-1/src/client/Home.tsx
- 起動処理、リストデータ取得
const fetchItems = async () => {
try {
setLoading(true);
const data = await itemsApi.getAll(CONTENT);
console.log(data);
setItems(data);
} catch (err) {
setError('アイテムの取得に失敗しました');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchItems();
}, []);
- API連携
- headless-app-1/src/routes/todos.ts
- 外部API連携、レスポンスをフロント側に返す。
router.post('/list', async function(req: any, res: any) {
try {
const body = req.body;
console.log(body)
const url = process.env.EXTERNAL_API_URL;
const apikey = process.env.API_KEY;
const path = "/api/data/list?content=" + CONTENT
console.log("url=", url + path)
const response = await fetch(url + path, {
method: 'GET',
headers: {
'Authorization': apikey,
}
});
if(response.ok === false){
console.error("Error, res.ok = NG");
throw new Error("Error, res.ok = NG");
}
const json = await response.json();
res.send({ret: 200, data: json.data});
} catch (error) {
console.error(error);
res.sendStatus(500);
}
});

SQLite WASM , フロント側 項目ソートなど
- フロント側内容になり。SQLite WASM + Headless CMS 構成
- bun + Reactで作成。
- 画面一覧で、項目指定ソートが難航したので、SQLiteにデータ追加し ソート実装
- データは、メモリ保存。
- 起動時に、APIから SQLiteにデータ登録( 項目は、一覧に見える項目のみ )
関連
環境
- SQLite WASM (sql.js 1.13.0)
- bun 1.2.20
- React
書いたコード
- .env
- EXTERNAL_API_URL: 接続API URRL
- API_KEY: Headless CMS に設定した API_KEY
EXTERNAL_API_URL="http://localhost:8787"
API_KEY=123
- dev-start
npm run build
npm run dev
- SQLite 初期化: 画面起動時
- headless-app-2/src/client/Sort/db.ts
init: async function() {
try{
const sql = await initSqlJs({
locateFile: file => `https://cdn.jsdelivr.net/npm/sql.js@1.13.0/dist/${file}`
});
const sqldb = new sql.Database();
sqldb.run(`CREATE TABLE IF NOT EXISTS items (
id TEXT,
name TEXT,
age INTEGER,
weight INTEGER
);`);
return sqldb;
}catch(e){
console.log(e);
throw new Error("error, init")
}
},
- APIからデータ追加
addItem: async function(db: any, values: any[]) {
try{
values.forEach((element) => {
//console.log("id", element.id);
//console.log(element.data);
let sql = `INSERT INTO items (id, name, age ,weight)
VALUES
(
'${element.id}',
'${element.data.name}' ,
${element.data.age} ,
${element.data.weight}
);
`;
//console.log(sql);
const res = db.run(sql);
});
}catch(e){
console.log(e);
throw new Error("error, addItem")
}
},
- sort: 画面イベント処理から、指定列のソート
sortItem: async function(db: any, colname: string, order: string) {
try{
let order_sql = "ASC";
if(order !== "asc"){
order_sql = "DESC"
}
const sql = `SELECT id, name, age ,weight FROM items
ORDER BY ${colname} ${order_sql}
;`;
console.log(sql);
const res = await db.exec(sql);
console.log(res);
if(!res[0]){
return [];
}
const out = [];
res[0].values.forEach((row) => {
//console.log(row);
let target = {
id: row[0],
name: row[1],
age: row[2] ,
weight: row[3]
}
out.push(target)
})
return out;
}catch(e){
console.log(e);
throw new Error("error, sortItem")
}
},

Postgres Rust Axum , Headless CMS
- Postgres + Axum、Headless CMS作成メモになります。
- 今回は、サバーレスではなく。セルフホスト等でデプロイ想定です。
環境
- Axum
- Postgres
- rustc 1.88.0 , cargo 1.88.0
- node 20
書いたコード
API使い方
- .env
- API_KEY: Headless CMS に設定した API_KEY
API_KEY=123
- dev-start
npm run build
npm run dev
- table
CREATE TABLE IF NOT EXISTS hcm_data (
id SERIAL NOT NULL,
content TEXT NOT NULL,
data TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now(),
updated_at TIMESTAMP NOT NULL DEFAULT now()
);
例: node.js: List
node.js
your-key: API_KEY , .env に設定した API_KEY
content: データ種類
const start = async function() {
try{
const response = await fetch("http://localhost:3000/api/data/list?content=test2&order=desc", {
method: 'GET',
headers: {
'Authorization': 'your-key',
}
});
if (!response.ok) {
const text = await response.text();
console.log(text)
throw new Error('Failed to create item');
}
const json = await response.json();
console.log(json)
}catch(e){console.log(e)}
}
start();
- create
- Create
- your-key: API_KEY , .env に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const item = {
content: "test2",
data: JSON.stringify({
"title": "tit-22",
"body": "body-22",
})
}
const response = await fetch("http://localhost:3000/api/data/create", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'your-key',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
}
return response.json();
}catch(e){console.log(e)}
}
start();

GoLang + Postgres , Headless CMS
- GoLang + Postgres、Headless CMS作成メモになります。
- 今回は、サバーレスではなく。セルフホスト等でデプロイ想定です。
環境
- go 1.24.4
- Postgres
- node 20
書いたコード
API使い方
- .env
- API_KEY: Headless CMS に設定した API_KEY
API_KEY=123
- dev-start
npm run build
go run .
- 例: node.js: List
- node.js
- your-key: API_KEY , .env に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const response = await fetch("http://localhost:8080/api/data/list?content=test2&order=desc", {
method: 'GET',
headers: {
'Authorization': 'your-key',
}
});
if (!response.ok) {
const text = await response.text();
console.log(text)
throw new Error('Failed to create item');
}else{
const json = await response.json();
console.log(json)
}
}catch(e){console.log(e)}
}
start();
- create
- Create
- your-key: API_KEY , .env に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const item = {
content: "test2",
data: JSON.stringify({
"title": "tit-12d1",
"body": "body-12d1",
})
}
const response = await fetch("http://localhost:8080/api/data/create", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'your-key',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
} else{
console.log("OK");
}
}catch(e){console.log(e)}
}
start();

Rust , Turso databse , Headless CMS
- rust Turso databse , headlessCMS作成メモになります。
- 今回は、サバーレスではなく。セルフホスト等でデプロイ想定です。
環境
- Rust Axum
- cargo 1.90.0
- Turso SDK Rust
- node 22
書いたコード
API使い方
- .env
- API_KEY: Headless CMS に設定した API_KEY
API_KEY=123
TURSO_DATABASE_URL=""
TURSO_AUTH_TOKEN=
- dev-start
cargo run --release
- table , todoに書き込む場合
CREATE TABLE IF NOT EXISTS todo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
data TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
- 例: node.js: List
- node.js
- your-key: API_KEY , .env に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const response = await fetch("http://localhost:3000/api/data/list?content=todo&order=asc", {
method: 'GET',
headers: {
'Authorization': 'your-key',
}
});
if (!response.ok) {
const text = await response.text();
console.log(text)
throw new Error('Failed to create item');
}
const json = await response.json();
console.log(json)
}catch(e){console.log(e)}
}
start();
- Create
- your-key: API_KEY , .env に設定した API_KEY
- content: データ種類
const start = async function() {
try{
const item = {
content: "todo",
data: JSON.stringify({
"title": "tit24",
"body": "body24",
})
}
const response = await fetch("http://localhost:3000/api/data/create", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'your-key',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
}else{
console.log("OK");
const json = await response.json();
console.log(json);
}
}catch(e){console.log(e)}
}
start();