FastAPIは、Pythonで構築されたモダンで高性能なWebフレームワークです。主にWeb APIの開発に特化しており、その使いやすさとパフォーマンスの高さから、シンプルなアプリケーションから大規模なプロジェクトまで幅広く利用されています。
今回はこのFastAPIを使用してSQLiteのデータベースと連携するWeb APIを作成し、さらにVue.jsとJavaScript開発ライブラリ「Wijmo(ウィジモ)」で作成したフロントエンドアプリケーションと連携して、データの生成(Create)、読込(Read)、更新(Update)、削除(Delete)を行う方法をご紹介します。

バックエンド
Web APIの作成
今回はPythonの標準データベースであるSQLiteを使用して、GET(参照)、POST(登録)、PUT(更新)、DELETE(削除)といったCRUD処理を行うWeb APIを作成します。
まずはvenvを使って新しく「fastapi-backend」という仮想環境を作成します。
python -m venv fastapi-backend
「fastapi-backend」フォルダに移動し、仮想環境を有効化します。
cd fastapi-backend
Scripts\activate
次にFastAPIとASGI Webサーバの「Uvicorn」、Pythonで使えるORMの「SQLAlchemy」をpip経由でインストールします。
pip install fastapi uvicorn sqlalchemy
インストールが完了したらプロジェクトのルートに「app」フォルダを作成し、「__init__.py」ファイルを作成します(中身は空でOKです)。

続けて同フォルダに「database.py」ファイルを作成し、データベース接続の設定を記載します。
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
次に「models.py」を作成し、SQLAlchemyのモデル定義を記載します。
from sqlalchemy import Column, Integer, String
from .database import Base
class Order(Base):
__tablename__ = "orders"
id = Column('id', Integer, primary_key=True)
productName = Column('productName', String)
orderDate = Column('orderDate', String)
amount = Column('amount', Integer)
次に「schemas.py」を作成し、バリデーションなどを担うPydanticのスキーマ定義を記載します。
from datetime import datetime
from pydantic import BaseModel
class Order(BaseModel):
productName: str
orderDate: datetime
amount: int
次に「crud.py」を作成し、CRUD処理を行うヘルパー関数の定義を記載します。
from sqlalchemy.orm import Session
from . import models, schemas
def get_order(id: int, db_session: Session):
return db_session.query(models.Order).filter(models.Order.id == id).first()
def create_order(order: schemas.Order, db: Session):
db_order = models.Order(productName=order.productName, orderDate=order.orderDate, amount=order.amount)
db.add(db_order)
db.commit()
db.refresh(db_order)
return db_order
def update_order(id: int, order: schemas.Order, db: Session):
db_order = get_order(id,db)
db_order.productName = order.productName
db_order.orderDate = order.orderDate
db_order.amount = order.amount
db.commit()
db.refresh(db_order)
return db_order
def delete_order(id: int, db: Session):
db_order = get_order(id,db)
if db_order is None:
return None
db.delete(db_order)
db.commit()
return db_order
最後にアプリケーション本体の「main.py」を作成します。CORSの設定も行い、これから作成するVueアプリのオリジンを設定します。
from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session
from . import crud, models, schemas
from .database import engine, get_db
from starlette.middleware.cors import CORSMiddleware
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
# CORS対応
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)
# 受注情報を全件取得
@app.get("/orders/")
def read_orders(db: Session = Depends(get_db)):
orders = db.query(models.Order).all()
return orders
# 受注情報を1件取得
@app.get("/orders/{order_id}")
def read_order(order_id: int, db: Session = Depends(get_db)):
order = crud.get_order(order_id, db)
return order
# 受注情報の登録
@app.post("/orders/")
def create_order(order: schemas.Order, db: Session = Depends(get_db)):
return crud.create_order(order=order, db=db)
# 受注情報の更新
@app.put("/orders/{order_id}")
def update_order(order_id: int, order: schemas.Order, db: Session = Depends(get_db)):
db_order = crud.update_order(id=order_id, order=order, db=db)
if db_order is None:
raise HTTPException(status_code=404, detail="Order not found")
return db_order
# 受注情報の削除
@app.delete("/orders/{order_id}")
def delete_order(order_id: int, db: Session = Depends(get_db)):
db_order = crud.delete_order(id=order_id, db=db)
if db_order is None:
raise HTTPException(status_code=404, detail="Order not found")
return db_order
Web APIの実行
以上でWeb APIの作成が完了したので実行してみます。以下のコマンドでAPIを起動します。
uvicorn app.main:app --reload
起動後、「http://127.0.0.1:8000/docs」にアクセスすると、自動生成されたOpenAPIのAPIドキュメントが表示されます。

APIドキュメント上で各種APIの動作を確認できます。まずはPOSTのAPIを実行し受注情報を登録します。
次にGETのAPI(「http://127.0.0.1:8000/orders/1」)を実行し、今登録した受注情報を取得します。
以下のように「http://127.0.0.1:8000/orders」でGETを実行すれば受注情報の全件取得もできます。
※ あらかじめ何件かデータを登録しています。
次にPUTのAPI(「http://127.0.0.1:8000/orders/1」)を実行し、受注情報を更新します。
さらにDELETEのAPI(「http://127.0.0.1:8000/orders/1」)を実行し、受注情報を削除します。
再度「http://127.0.0.1:8000/orders」のGETリクエストを実行し、正しく受注情報が削除されていることを確認します。
フロントエンド
FastAPIを使用したバックエンドのWeb APIが作成できましたので、そのAPIと連携するフロントエンドのアプリをVue.jsとWijmoで作成していきます。npmを使用しますので、あらかじめNode.jsのインストールが必要です。
Vueアプリケーションの作成
まずはcreate-vueを利用して、Vueアプリケーションを作成します。
npm create vue@latest
create-vueがインストールされていない場合は、上記のコマンド実行時に以下のようなメッセージが表示されインストールを促されます。Yキーを押下してインストールを行います。
Need to install the following packages:
create-vue@3.14.0
Ok to proceed? (y)
今回プロジェクト名には「wijmo-frontend」を設定しました。
? Project name: » wijmo-frontend
上記のほか、create-vueによって様々なオプションの選択を求められますが、今回は「Add TypeScript?」のみYesを選択してTypeScriptを追加し、その他のオプションはすべてデフォルトの「NO」を選択してシンプルなアプリケーションを作成します。
√ Project name: ... wijmo-frontend
√ Add TypeScript? ... No / Yes
√ Add JSX Support? ... No / Yes
√ Add Vue Router for Single Page Application development? ... No / Yes
√ Add Pinia for state management? ... No / Yes
√ Add Vitest for Unit Testing? ... No / Yes
√ Add an End-to-End Testing Solution? » No
√ Add ESLint for code quality? » No
プロジェクトを作成したら、動作確認のために実行してみます。以下のコマンドを実行してプロジェクトフォルダ「wijmo-frontend」に移動します。
cd wijmo-frontend
次に以下のコマンドを実行してアプリケーションを起動します。
npm install
npm run dev
ブラウザで「http://localhost:5173/」を開くと以下のようにVueアプリケーションの実行を確認できます。

動作を確認したらCtrl+Cキーを押下して終了しておきます。
Wijmoのインストールとアプリへの組み込み
「npm install」コマンドを実行して、WijmoのVue.js用パッケージをアプリケーションにインストールします。
npm install @mescius/wijmo.vue2.all
「src/App.vue」ファイルを編集し、WijmoのFlexGridをアプリに組み込んでいきます。まずはWijmoの各種コンポーネントのインポートやCRUD処理の実装を行います。シンタックスシュガー(糖衣構文)の<script setup>
を使用して記述しています。
url
には先ほど作成したFastAPIのURLを設定し、WijmoのhttpRequestメソッドを使用してWeb APIからデータを取得します。また、FlexGrid上で行われた変更箇所はCollectionViewを使って追跡します。
[更新]押下時に実行される「update」関数では登録、更新、削除の処理を行っており、FlexGrid上で行われた変更内容が格納される「customer.itemsEdited」「customer.itemsAdded」「customer.itemsRemoved」の3つの配列を参照してリクエストをそれぞれ送信します。また、reviver関数の中では日付項目が格納されたstring型の項目に対し、Date型に変換する処理を行っています。
※ ライセンスキーを設定しない場合トライアル版を示すメッセージが表示されます。ライセンスキーの入手や設定方法についてはこちらをご覧ください。
<script setup>
import { onMounted } from "vue";
//Wijmoのコンポーネントをインポートします。
import * as wjCore from "@mescius/wijmo";
import { WjFlexGrid, WjFlexGridColumn } from '@mescius/wijmo.vue2.grid';
//日本語化カルチャをインポートします。
import '@mescius/wijmo.cultures/wijmo.culture.ja';
//wjCore.setLicenseKey('ここにライセンスキーの文字列を設定します');
const url = "http://127.0.0.1:8000/orders";
const order = new wjCore.CollectionView([], { trackChanges: true });
// データ取得 (GET)
onMounted(() => {
wjCore.httpRequest(url, {
success: (xhr) => {
const data = JSON.parse(xhr.response, reviver);
order.sourceCollection = data;
},
});
});
// 更新処理 (PATCH, POST, DELETE)
const update = () => {
// データ更新(PATCH)
order.itemsEdited.forEach((item) => {
wjCore.httpRequest(`${url}/${item.id}`, {
method: "PUT",
data: item,
});
});
// データ登録(POST)
order.itemsAdded.forEach((item) => {
wjCore.httpRequest(url, {
method: "POST",
data: item,
});
});
// データ削除(DELETE)
order.itemsRemoved.forEach((item) => {
wjCore.httpRequest(`${url}/${item.id}`, {
method: "DELETE",
});
});
};
const reviver = (key, val) => {
// 先頭から"yyyy-mm-dd"の文字列を日付データと判断
if (typeof (val) == "string" &&
val.match(/^\d{4}-\d{2}-\d{2}.*/)) {
return new Date(Date.parse(val)); // Date型に変換
} return val;
};
</script>
さらに<template>
で更新処理を実行するボタンやFlexGridの表示部分の定義を行います。WjFlexGridColumnコンポーネントでは各カラムのプロパティの値を設定しています。
<template>
<button @click="update" class="button">更新</button>
<wj-flex-grid :autoGenerateColumns=false :itemsSource="order" :allowAddNew="true" :allowDelete="true">
<wj-flex-grid-column header="ID" binding="id" :width="60"></wj-flex-grid-column>
<wj-flex-grid-column header="商品名" binding="productName" :width="200"></wj-flex-grid-column>
<wj-flex-grid-column header="受注日" binding="orderDate" :width="120" format='yyyy/M/d'></wj-flex-grid-column>
<wj-flex-grid-column header="金額" binding="amount" :width="100" format="c"></wj-flex-grid-column>
</wj-flex-grid>
</template>
続けて<style>
でWijmoのCSSファイルのインポートや各種スタイルの定義を行います。
<style>
/* Wijmoのスタイルファイルをインポートします */
@import '@mescius/wijmo.styles/wijmo.css';
body {
margin: 10px 0px 0px 10px;
}
.button {
font-size: 12px;
margin-bottom: 10px;
}
.wj-flexgrid {
width: 530px;
}
</style>
「src/App.vue」ファイル全体の内容は以下のようになります。
<script setup>
import { onMounted } from "vue";
//WjFlexGridコンポーネントをインポートします。
import * as wjCore from "@mescius/wijmo";
import { WjFlexGrid, WjFlexGridColumn } from '@mescius/wijmo.vue2.grid';
//日本語化カルチャをインポートします。
import '@mescius/wijmo.cultures/wijmo.culture.ja';
//wjCore.setLicenseKey('ここにライセンスキーの文字列を設定します');
const url = "http://127.0.0.1:8000/orders";
const order = new wjCore.CollectionView([], { trackChanges: true });
// データ取得 (GET)
onMounted(() => {
wjCore.httpRequest(url, {
success: (xhr) => {
const data = JSON.parse(xhr.response, reviver);
order.sourceCollection = data;
},
});
});
// 更新処理 (PATCH, POST, DELETE)
const update = () => {
// データ更新(PATCH)
order.itemsEdited.forEach((item) => {
wjCore.httpRequest(`${url}/${item.id}`, {
method: "PUT",
data: item,
});
});
// データ登録(POST)
order.itemsAdded.forEach((item) => {
wjCore.httpRequest(url, {
method: "POST",
data: item,
});
});
// データ削除(DELETE)
order.itemsRemoved.forEach((item) => {
wjCore.httpRequest(`${url}/${item.id}`, {
method: "DELETE",
});
});
};
const reviver = (key, val) => {
// 先頭から"yyyy-mm-dd"の文字列を日付データと判断
if (typeof (val) == "string" &&
val.match(/^\d{4}-\d{2}-\d{2}.*/)) {
return new Date(Date.parse(val)); // Date型に変換
} return val;
};
</script>
<template>
<button @click="update" class="button">更新</button><br/>
<wj-flex-grid :autoGenerateColumns=false :itemsSource="order" :allowAddNew="true" :allowDelete="true">
<wj-flex-grid-column header="ID" binding="id" :width="60"></wj-flex-grid-column>
<wj-flex-grid-column header="商品名" binding="productName" :width="200"></wj-flex-grid-column>
<wj-flex-grid-column header="受注日" binding="orderDate" :width="120" format='yyyy/M/d'></wj-flex-grid-column>
<wj-flex-grid-column header="金額" binding="amount" :width="100" format="c"></wj-flex-grid-column>
</wj-flex-grid>
</template>
<style>
/* Wijmoのスタイルファイルをインポートします */
@import '@mescius/wijmo.styles/wijmo.css';
body {
margin: 10px 0px 0px 10px;
}
.button {
font-size: 12px;
margin-bottom: 10px;
}
.wj-flexgrid {
width: 530px;
}
</style>
最後に「src/assets/main.css」に記載されている既存のスタイルを削除します。
@import './base.css';
データの取得(READ)
以上の手順で、Wijmoの組み込みは完了です。再び「npm run dev」コマンドを実行して「http://localhost:5173/」にアクセスすると、FlexGrid上にAPIから取得したデータが表示されていることを確認できます。
※ 事前に冒頭で作成したFastAPIのWeb APIを起動しておいてください。

データの登録(CREATE)
FlexGridの一番下の行にデータを入力することで新規データの登録が可能です。データ入力後[更新]ボタンを押下するとAPIに登録のリクエストを送信できます。
データの更新(UPDATE)
FlexGrid上で任意のデータを更新し、[更新]ボタンを押下するとAPIに更新のリクエストを送信できます。一度に複数のレコードを更新することも可能です。
データの削除(DELETE)
FlexGrid上で削除したい行を選択しDeleteキーを押下すると対象の行を削除できます。その後、[更新]ボタンを押下するとAPIに削除のリクエストを送信できます。
さいごに
以上がFastAPIを使用してWeb APIを作成し、Vue.jsとWijmoを使ったフロントエンドアプリと連携する方法でした。
WebサイトではWijmoの機能を手軽に体験できるデモアプリケーションやトライアル版も公開しておりますので、こちらもご確認ください。
また、ご導入前の製品に関するご相談、ご導入後の各種サービスに関するご質問など、お気軽にお問合せください。