はじめに
Azure Functions ( 実行環境 : Node
, 使用言語 : TypeScript
) から、
Mongo DB ( Azure Cosmos DB
) を操作する方法について調査したのでまとめておきます。
検証環境
- 開発用PC ( OS : Windows 10 Pro )
- Node.js
v16.13.2
- mongoose
6.1.9
- typescript
3.9.10
- @azure/functions
1.2.3
- mongoose
- Azure Functions Core Tools
v4.0.3971
- Postman ( テスト用 )
- cURL でも対応
- Visual Studio Code
手順
1. ローカル関数プロジェクトを作成する
Azure Functions Core Tools を使用して、ローカルプロジェクトを生成する。
> func init MongoDBTest
Use the up/down arrow keys to select a worker runtime: node
ランタイムは node
を選択します。
![image.png (136.9 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2F88adb069-8911-4027-8341-5d4d38b78926.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=66ec29aceeeee81c1a36ad563c01ccd7)
Use the up/down arrow keys to select a language: typescript
使用言語は TypeScript
を選択します。
![image.png (139.9 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2F8e52ab1e-e2d2-4890-ac8e-42e0629517ec.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=37aca426a054e6e42c8ac8f5a3b65f48)
ランタイム (実行環境) と 使用言語 の選択が終了すると、
必要なファイルがローカル関数PJディレクトリ配下に生成されます。
![image.png (568.7 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2Fb4d8d576-3ee3-4292-8fda-d354cbbc1432.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=79124e8f2440656758178ea5fb1b2ebd)
2. ローカル関数を作成する
新規作成したプロジェクトのルートディレクトリへ移動して、
ローカル関数を作成するコマンドを実行します。
> cd ./MongoDBTest
> func new --template "Http Trigger" --name User
上記サンプルの場合、ルートディレクトリ配下に User
ディレクトリが作成されます。
ローカル関数の functions.json
, index.tx
はこの User
ディレクトリ配下に保存されます。
ローカル関数の作成手順はこれで終了です。
ルートディレクトリに戻り、以下コマンドを実行すると
ローカル関数を起動することができます。
> cd ..
> npm install
> npm start
3. Azure Cosmos DB を作成する
データを保存するための Azure Cosmos DB を作成します。
( Mongo DB on Azure Cosmos DB 作成方法は、公式ドキュメントをご覧ください。)
Cosmos DB のデプロイが完了したら、ナビゲーションメニューより
[設定] > [接続文字列] を選択します。
![image.png (246.7 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2F45913806-304e-404d-94eb-d2ca2b90a174.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=42b69bc812bf976535b9d3d55d5864a0)
接続文字列が表示されるので、プライマリ接続文字列 をコピーします。
![image.png (246.7 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F180432%2F38bbaa78-ec95-d161-8139-20201c3184c2.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=563f92986962d653c2c7c3284ab7ef2a)
※ プライマリ接続文字列は、Node アプリケーションから
Cosmos DB ( Mongo DB ) へ接続する際に使用します。
4. ローカル関数から Cosmos DB にデータを保存する
ローカル関数から Mongo DB ( Cosmos DB ) へ接続するために、
mongoose
をインストールします。
> npm install mongoose --save
ルートディレクトリの local.settings.json
を開き、
Value オブジェクトに CosmosDBConnectionString
を追加します。
{
"Values": {
"FUNCTIONS_WOKER_RUNTIME": "node",
"CosmosDBConnectionString": "<--- Azure Cosmos DB 接続文字列 --->"
}
}
- local.settings.json は ローカル関数を実行する際に読み込まれる設定になります。
Azure 上へデプロイする際には含めることができないので、Key Vault 等を使用して
接続文字列等の機密性の高い情報を取り扱うようにしてください。 - Azure Functions をローカルでコーディングしてテストする
Mongo DB 接続用の TypeScript ファイルを lib フォルダ配下に追加します。
( ※ lib フォルダが存在しない場合は、新規作成します。)
import { Schema, model, connect } from "mongoose";
let db = null;
const UserSchema = new Schema(
{ name: String },
{ timestamps: true }
);
const UserModel = model("User", UserSchema, "Users");
export const init = async () => {
if(!db) {
db = await connect(process.env["CosmosDbConnectionString"]);
}
};
export const addItem = async (doc) => {
const modelToInsert = new UserModel();
modelToInsert["name"] = doc.name;
return await modelToInsert.save();
};
export const findItemById = async (id) => {
return await UserModel.findById(id);
};
export const findItems = async (query = {}) => {
return await UserModel.find({});
};
export const deleteItemById = async (id) => {
return await UserModel.findByIdAndDelete(id);
};
azure-cosmosdb-mongodb.ts
で export した関数をインポートして、
ローカル関数から Mongo DB ( Cosmos DB ) への接続、データのストアを行います。
import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import * as db from "../lib/azure-cosmosdb-mongodb";
const User: AzureFunction = async function (
context: Context,
req: HttpRequest
): Promise<void> {
try {
let response = null;
// Mongo DB ( Cosmos DB ) への接続
await db.init();
// Request メソッドに応じて処理を振り分け
switch (req.method) {
case "GET":
if (req?.query.id || (req?.body && req?.body?.id)) {
response = {
documentResponse: await db.findItemById(req?.body?.id),
};
} else {
// リクエストパラメーターが存在しない場合は、コレクション一覧を取得する
const dbQuery =
req?.query?.dbQuery || (req?.body && req?.body?.dbQuery);
response = {
documentResponse: await db.findItems(dbQuery),
};
}
break;
case "POST":
if (req?.body?.document) {
const insertOneResponse = await db.addItem(req?.body?.document);
response = {
documentResponse: insertOneResponse,
};
} else {
throw Error("No document found");
}
break;
case "DELETE":
if (req?.query?.id || (req?.body && req?.body?.id)) {
response = {
documentResponse: await db.deleteItemById(req?.body?.id),
};
} else {
throw Error("No id found");
}
break;
default:
throw Error(`${req.method} not allowed`)
}
context.res = {
body: response,
};
} catch (err) {
context.log(`*** Error throw: ${JSON.stringify(err)}`);
context.res = {
status: 500,
body: err,
};
}
};
export default User;
functions.json
を開き、bindings
オブジェクトの
methods
配列に "delete" を追加します。
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post",
"delete"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
],
"scriptFile": "../dist/User/index.js"
}
以上で、ローカル関数 ( Azure Functions ) から Mongo DB へ接続、
データを保存することが可能になります。
5. 実際にローカル関数を動かしてみる
ローカル関数 ( Azure Functions ) をローカルで起動します。
> npm start
起動後、以下出力があるので、URL をコピーします。
Functions:
User: [GET, POST, DELETE] http://localhost:7071/api/User
まず GET (リクエストパラメーターなし) でリクエストしてみます。
→ まだデータを登録していないので、空のオブジェクトが返ってきました。
![image.png (60.4 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2F3cb6dba0-fc27-4ae2-977d-e35bb1602be9.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=93e2cbc4667263ab4eed3e1706960999)
続いて、POST (リクエストボディ/ name : XXXXXXX) でリクエストしてみます。
→ データが正常登録されました。
![image.png (73.6 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2Fa027891d-597b-4dd7-b99e-dd15e7c1397b.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=c962acc8915f1f4d8a84874751d5d678)
再度、GET (リクエストパラメーターなし) でリクエストしてみると...
→ User コレクション一覧を取得することができました。
![image.png (71.5 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2F9d127259-a6a9-4a88-bcc2-a12c154ae655.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=986790da5cb19eb7e992ed5592aa5dce)
最後に Delete ( リクエストボディ / id : xxxxxxxxxxxxxxxxxxxxx ) を実行。
→ 対象のデータが削除できました。
![image.png (71.4 kB)](https://qiita-user-contents.imgix.net/https%3A%2F%2Fimg.esa.io%2Fuploads%2Fproduction%2Fattachments%2F3505%2F2022%2F02%2F02%2F10862%2F85b0918c-9f7c-4c79-bc2b-3e8ea58894de.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=eac04640498edb8b497ae45f77b94d6a)
以上、Azure Functions から Mongo DB を操作する方法でした。
終わりに
Azure Functions Core Tools
を使うと、コマンド一発で Azure 上にもデプロイできるので凄い便利ですね。今は Azure CLI でリソースグループの作成、リソースのデプロイをやってるんですが、慣れてきたら ARM ( Azure Resource Manager ) テンプレートを使ってデプロイしてみたいなと思います。Azure は楽しい!