はじめに
Oracle Cloud Infrastructure (OCI) の Autonomous Database (ADB) には、データベースのテーブルを自動的にREST API化するORDS (Oracle REST Data Services) という機能が標準で備わっています。
今回はこれらを使って、Reactで簡易なToDoアプリを作ってみたいと思います。
構成は、全てのコンポーネントで OCI Always Free (永久無料枠) を使用するため、無料で構築可能です。
インターネットに抜ける通信料(アウトバウンド転送量)は10TB/月を超えると有償になるのでご注意ください。
(これだけだと超えることはほぼ無いと思いますが…)
アーキテクチャ
-
Database: OCI Autonomous AI Database Always Free
- API: ORDS
-
Server: OCI Compute (Oracle Linux 8, VM.Standard.A1.Flex)
- Frontend: React
1. OCI Autonomous Databaseの準備
まずはOCIコンソールからAutonomous Databaseを作成します。
- ワークロード:レイクハウス(トランザクション処理でも良いです)
- データベースハージョン:26ai
- Always Free:チェック(忘れずに!)
- ネットワーク・アクセス:すべての場所からの…(検証用。適宜変更ください)
Always Freeにチェックが入っていることを忘れずに確認ください!
作成が完了したら、Database Actions (SQL Developer Web) を開きます。
1-1. Todoテーブルの作成
以下のクエリを実行してテーブルを作成します。
CREATE TABLE todos (
id NUMBER GENERATED ALWAYS AS IDENTITY,
title VARCHAR2(255) NOT NULL,
is_completed NUMBER(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT todos_pk PRIMARY KEY (id)
);
更新ボタンでTODOSテーブルが表示されればOKです。
1-2. ORDS (REST API) の有効化
作成したテーブルをREST APIとして公開します。
- 先程のSQL画面から表示された左側のリストから
TODOSテーブルを探します(表示されない場合はスキーマがあっているか確認してください)。 -
TODOSテーブルを右クリック(またはメニューから)し、REST → 有効化 を選択します。
- 設定ダイアログで以下のように設定します。
-
オブジェクト別名 (Alias):
todos(これがURLの一部になります) - 認証が必要 (Authentication): 今回は簡易作成のためチェックを外す (※本番ではOAuth2などを設定すべきですが、デモ用としてパブリックにします)
-
オブジェクト別名 (Alias):
- 有効化をクリックします。
たったこれでAPIが完成しました!
同じく左側のリストのTODOSを右クリックし、cURLコマンド…をクリックすることで、RESTエンドポイントURL が確認可能です。
(例: https://<unique-id>.adb.<region>.oraclecloudapps.com/ords/admin/todos/)
このURLに対して標準的なHTTPメソッド(GET, POST, PUT, DELETE)を送るだけでDML操作が可能です。
2. Reactプロジェクトの作成
クライアントPC側でまずは動作確認を行います。
不要な場合は3章へ飛ばしてOKです。
フロントエンドを構築します。ビルドツールにはViteを使用します。
npm create vite@latest todo-app -- --template react
cd todo-app
npm install
2-1. 環境変数の設定
プロジェクトルートに .env ファイルを作成し、先ほどコピーしたORDSのURLを設定します。
vim ./.env
VITE_API_URL=https://<unique-id>.adb.<region>.oraclecloudapps.com/ords/admin/todos/
2-2. アプリの実装
src/App.jsx を以下のように書き換えます。
import { useState, useEffect } from 'react'
const API_URL = import.meta.env.VITE_API_URL
function App() {
const [todos, setTodos] = useState([])
const [newTitle, setNewTitle] = useState('')
// Todo一覧の取得 (GET)
const fetchTodos = async () => {
try {
const res = await fetch(API_URL)
const data = await res.json()
// ORDSのAuto-RESTは { items: [...] } の形式で返します
setTodos(data.items)
} catch (err) {
console.error("Failed to fetch todos:", err)
}
}
// 初回レンダリング時に取得
useEffect(() => {
fetchTodos()
}, [])
// Todoの追加 (POST)
const addTodo = async (e) => {
e.preventDefault()
if (!newTitle) return
try {
await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: newTitle
})
})
setNewTitle('')
fetchTodos() // リスト再取得
} catch (err) {
console.error("Failed to add todo:", err)
}
}
// Todoの削除 (DELETE)
const deleteTodo = async (id) => {
try {
// Auto-RESTの仕様では /endpoint/:id で削除
await fetch(`${API_URL}${id}`, {
method: 'DELETE'
})
fetchTodos()
} catch (err) {
console.error("Failed to delete todo:", err)
}
}
// 完了状態の切り替え (PUT)
const toggleTodo = async (todo) => {
try {
await fetch(`${API_URL}${todo.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// 更新したいフィールドのみを送ることも可能ですが、
// Auto-RESTの場合は全カラムを送るのが安全な場合もあります。
// ここではシンプルに更新値を送ります。
id: todo.id,
title: todo.title,
is_completed: todo.is_completed === 1 ? 0 : 1
})
})
fetchTodos()
} catch (err) {
console.error("Failed to update todo:", err)
}
}
return (
<div style={{ padding: '2rem', maxWidth: '600px', margin: '0 auto' }}>
<h1>React + Oracle ADB Todo Apps</h1>
<form onSubmit={addTodo} style={{ marginBottom: '2rem' }}>
<input
type="text"
value={newTitle}
onChange={(e) => setNewTitle(e.target.value)}
placeholder="新しいタスクを入力..."
style={{ padding: '0.5rem', width: '70%' }}
/>
<button type="submit" style={{ padding: '0.5rem', marginLeft: '0.5rem' }}>追加</button>
</form>
<ul>
{todos.map(todo => (
<li key={todo.id} style={{ marginBottom: '0.5rem', listStyle: 'none', display: 'flex', alignItems: 'center' }}>
<input
type="checkbox"
checked={todo.is_completed === 1}
onChange={() => toggleTodo(todo)}
/>
<span style={{
marginLeft: '0.5rem',
textDecoration: todo.is_completed === 1 ? 'line-through' : 'none',
flexGrow: 1
}}>
{todo.title}
</span>
<button onClick={() => deleteTodo(todo.id)} style={{ marginLeft: '1rem', color: 'red' }}>削除</button>
</li>
))}
</ul>
</div>
)
}
export default App
2-3. ローカルでの動作確認
実装ができたら、まずはローカル環境で動作を確認します。
npm run dev
ブラウザで http://localhost:5173 (または表示されたURL)にアクセスします。
タスクの追加・削除・完了チェックなどの操作を行い、エラーなく動作することを確認してください。
先程ADB側で確認したDatabase ActionsのSQL側でテーブルを確認すると、実際にデータが反映されていることが分かります。
3. アプリケーションのデプロイ (OCI Compute)
作成したReactアプリをローカルだけでなく、OCI上のコンピュート・インスタンス(Oracle Linux 9)にデプロイしてWebサーバーとして公開する手順を解説します。
3-1. Computeインスタンスの作成
OCIコンソールからコンピュート・インスタンスを作成します。今回はパフォーマンスが高く、かつAlways Free枠で使える Ampere A1 インスタンスを使用します。
- イメージ: Oracle Linux 8 (aarch64)
-
シェイプ: VM.Standard.A1.Flex
- OCPU: 1〜4 (お好みで。4 OCPUまで無料)
- メモリ: 6〜24 GB (お好みで。24 GBまで無料)
※ VM.Standard.A1.Flex はARMアーキテクチャですが、Node.jsやNginxなどの主要なソフトウェアは通常通り動作します。
3-2. セキュリティリスト(ファイアウォール)の設定
作成したインスタンスが配置されているVCN(仮想クラウドネットワーク)のセキュリティリストを編集し、インターネットからのWebアクセス(ポート80)を許可します。
- OCIコンソールで該当のサブネットの詳細ページを開きます。
- 「セキュリティ・リスト」をクリックし、現在適用されているリストを選択します。
- 「イングレス・ルールの追加」をクリックし、以下を設定します。
-
ソースCIDR:
0.0.0.0/0(全IPからのアクセスを許可) - IPプロトコル: TCP
-
宛先ポート範囲:
80
-
ソースCIDR:
3-3. サーバーのセットアップ
作成したインスタンスにSSHで接続し、Webサーバー(Nginx)とビルド用環境(Node.js)をインストールします。
ARMアーキテクチャであっても、手順はx86_64と変わりません。
# パッケージの更新
sudo dnf update -y
# Nginxのインストールと起動
sudo dnf install nginx -y
sudo systemctl enable --now nginx
# Firewalldの設定 (OSレベルでのポート開放)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
この時点で、ブラウザから http://<インスタンスのパブリックIP> にアクセスすると、Nginxのデフォルトページが表示されるはずです。
3-4. アプリケーションのビルドと配置
サーバー上でアプリケーションをビルドし、公開ディレクトリに配置します。
まず、Node.jsをインストールします(既にインストール済みの場合はスキップ)。
# Node.js 20系の有効化とインストール
sudo dnf module enable nodejs:20 -y
sudo dnf install nodejs -y
次に、ViteでReactプロジェクトの雛形を作成します。
# ホームディレクトリなどで実行
cd ~
npm create vite@latest todo-app -- --template react
cd todo-app
npm install
src/App.jsx を vim 等のエディタで開き、前述の「2-2. アプリの実装」で作成したコードをコピペして上書きします。
vim src/App.jsx
# ここで中身を全て消去し、コードを貼り付けて保存 (:wq)
同様に、環境変数ファイル .env.production を作成し、ADBのURLを記述します。
vim .env.production
Content of .env.production:
VITE_API_URL=https://<unique-id>.adb.<region>.oraclecloudapps.com/ords/admin/todos/
ファイルの準備ができたら、ビルドを実行します。
# ビルド実行
npm run build
ビルドが完了すると dist ディレクトリが生成されます。
この中身をNginxのドキュメントルートにコピーします。
# Nginxのデフォルトファイルを削除
sudo rm -rf /usr/share/nginx/html/*
# ビルド成果物をドキュメントルートにコピー
sudo cp -r dist/* /usr/share/nginx/html/
# 権限の修正 (念のためNginxユーザーが読み取れるように)
sudo chown -R nginx:nginx /usr/share/nginx/html
sudo chmod -R 755 /usr/share/nginx/html
3-5. 動作確認
ブラウザで http://<インスタンスのパブリックIP> にアクセスしてください。
Reactで作ったTodoアプリが表示され、同じように追加したタスクがADBに保存されることが確認できれば成功です!

おわりに
OCI Autonomous DatabaseのORDS機能を使えば、バックエンドサーバーを構築することなくDB操作を行うことができます。
さらにOCI Computeと組み合わせることで、Webアプリケーション環境をすべてOCI上で構築することが可能です。
今回は認証なしで公開しましたが、ビジネス利用の際はADBはADMINユーザではなくユーザを作成の上テーブルを管理し、必ずORDS側でOAuth2認証などを設定し、Compute側も適切なセキュリティ対策(HTTPS化など)を実施してください。






