サーバーレス TypeScript API: Azure Functionsを使用して MongoDB にデータを格納する
Mongoose API を使用して Azure Cosmos DB にデータを格納する Azure Function API を作成し、パブリック HTTP エンドポイントを使用してホスティングするために関数アプリケーションを Azure クラウドにデプロイします。
Note
この記事では、現在プレビュー段階にある Azure Functions Node.js v4 プログラミング モデルを使用します。
開発環境を準備する
次のソフトウェアをインストールします。
- 無料の Azure サブスクリプションを作成します。
- LTS v18 以降Node.jsインストールする
- TypeScript v4 以降
- ローカル開発ストレージ用にグローバルにインストールされた Azurite
- Azure Functions Runtime v4.16 以降
- Azure Functions Core Tools v4.0.5095 以降 (ローカルで実行されている場合) がローカル開発用にグローバルにインストールされている
- Visual Studio Code をインストールし、次の拡張機能を使用します。
1. Visual Studio Code で Azure にサインインする
Azure サービスの拡張機能を既に使用している場合は、既にログイン済みなので、この手順を省略できます。
Visual Studio Code に Azure サービス拡張機能をインストールしたら、Azure アカウントにサインインする必要があります。
Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
[リソース] セクションで、[Azure にサインインする] を選択し、画面の指示に従います。
サインイン後、お使いの Azure アカウントのメール アドレスがステータス バーに表示されていることと、サブスクリプションが Azure エクスプローラーに表示されていることを確認します。
2. Azure リソース グループを作成する
リソース グループは、リソースのリージョン ベースのコレクションです。 リソース グループを作成し、そのグループ内にリソースを作成することによって、チュートリアルの最後に、各リソースを個別に削除することなく、リソース グループを削除できます。
Azure Functions プロジェクトのルートとして使用する新しいフォルダーをローカル システムに作成します。
Visual Studio Code でこのフォルダーを開きます。
Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
[リソース] でサブスクリプションを見つけて + アイコンを選択し、[リソース グループの作成] を選択ます。
プロンプトに入力するには、次の表を使用します。
Prompt 値 新しいリソース グループの名前を入力してください。 azure-tutorial
新しいリソースの場所を選択してください。 地理的に近い場所を選択します。
3. ローカルの関数アプリを作成する
HTTP トリガー関数を含むローカルの Azure Functions (サーバーレス) アプリケーションを作成します。
Visual Studio Code で、コマンド パレットを開きます (Ctrl + Shift + P)。
[Azure Functions: 新しいプロジェクトの作成] を検索して選択します。
次の表を使用して、ローカル Azure 関数プロジェクトの作成を完了します。
Prompt 値 メモ 関数プロジェクトを含むフォルダーを選択します 現在の (既定の) フォルダーを選択します。 言語を選択する TypeScript TypeScript プログラミング モデルを選択する モデル V4 (プレビュー) Select a template for your project's first function (プロジェクトの最初の関数のテンプレートを選択してください) HTTP トリガー API は、HTTP 要求を使用して呼び出されます。 Provide a function name (関数名を指定してください) blogposts
API ルートは /api/blogposts
Visual Studio Code によってプロジェクトが作成されたら、ファイル内の API コードを
./src/functions/blogposts.ts
表示します。import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions"; export async function blogposts(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> { context.log(`Http function processed request for url "${request.url}"`); const name = request.query.get('name') || await request.text() || 'world'; return { body: `Hello, ${name}!` }; }; app.http('blogposts', { methods: ['GET', 'POST'], authLevel: 'anonymous', handler: blogposts });
このコードは、新しい v4 プログラミング モデルの標準定型句です。 POST と GET を使用して API レイヤーを記述する唯一の方法を示すわけではありません。
前のコードを次のコードに置き換えて、GET 要求のみがすべてのブログ投稿を返せるようにします。
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions"; // curl --location 'http://localhost:7071/api/blogposts' --verbose export async function getBlogPosts(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> { context.log(`Http function getBlogPosts processed request for url "${request.url}"`); // Empty array for now ... will fix later const blogposts = []; return { status: 200, jsonBody: { blogposts } }; }; app.get('getBlogPosts', { route: "blogposts", authLevel: 'anonymous', handler: getBlogPosts });
このコードには、 v4 プログラミング モデルの変更Node.js Azure Functionsがいくつかあります。
- GET 要求であることを示す の
getBlobPosts
関数名は、ログ内の関数を分離するのに役立ちます。 - プロパティは
route
にblogposts
設定されています。これは、指定/api/blogposts
された既定の API ルートの一部である です。 - オブジェクトの
methods
を使用get
すると、これが GET 要求であることを示すのでapp
、 プロパティは削除され、不要です。 メソッド関数を次に示します。 別のメソッドがある場合は、 プロパティを使用してmethods
に戻ることができます。deleteRequest()
get()
patch()
post()
put()
- GET 要求であることを示す の
4. Azurite ローカル ストレージ エミュレーターを起動する
ローカル コンピューターで関数を開発するには、ストレージ エミュレーター (無料) または Azure Storage アカウント (有料) が必要です。
別のターミナルで、 Azurite ローカル ストレージ エミュレーターを起動します。
azurite --silent --location ./azurite --debug ./azurite/debug.log
これは、ローカルの Azure Storage エミュレーターを使用してローカルでAzure Functionsを実行するために必要です。 ローカル ストレージ エミュレーターは、AzureWebJobsStorage プロパティの値UseDevelopmentStorage=true
が のファイルで指定されますlocal.settings.json
。
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "node",
"AzureWebJobsFeatureFlags": "EnableWorkerIndexing"
}
}
azurite
サブフォルダーは既にファイルに.gitignore
追加されています。
5. ローカル サーバーレス関数を実行する
Azure にデプロイする前に、Azure Functions プロジェクトをローカルで実行してテストします。
Visual Studio Code で、getBlogPosts 関数の末尾にある ステートメントにブレークポイント
return
を設定します。Visual Studio Code で、F5 を押してデバッガーを起動し、Azure Functions ホストに接続します。
[デバッグ]>[デバッグの開始] メニュー コマンドを使用することもできます。
[ ターミナル ] パネルに出力が表示されます。
Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
[ワークスペース] セクションで、ローカル プロジェクト -Functions ->>getBlogPosts を見つけて展開します。
関数名を右クリックし、 getBlogPosts を選択し、[ 関数 URL のコピー] を選択します。
ブラウザーで URL を貼り付け、Enter キーを押すか、ターミナルで次のcURL コマンドを使用します。
curl http://localhost:7071/api/blogposts --verbose
ブログ投稿の空の配列の応答は、次のように返されます。
* Trying 127.0.0.1:7071... * Connected to localhost (127.0.0.1) port 7071 (#0) > GET /api/blogposts HTTP/1.1 > Host: localhost:7071 > User-Agent: curl/7.88.1 > Accept: */* > < HTTP/1.1 200 OK < Content-Type: application/json < Date: Mon, 08 May 2023 17:35:24 GMT < Server: Kestrel < Transfer-Encoding: chunked < {"blogposts":[]}* Connection #0 to host localhost left intact
VS Code で、デバッガー を停止します。Shift + F5 を押します。
6. Visual Studio Code で Azure 関数アプリを作成する
このセクションでは、Azure サブスクリプションに関数アプリ クラウド リソースと関連リソースを作成します。
Visual Studio Code で、コマンド パレットを開きます (Ctrl + Shift + P)。
[Azure Functions: Azure で関数アプリを作成する (詳細) を検索して選択します。
プロンプトで、次の情報を入力します。
Prompt [選択] 関数アプリのグローバルに一意の名前を入力してください URL パスで有効な名前を入力します (例: first-function
)。 URL をグローバルに一意にするには、3 文字をポストペンします。 入力した名前は、Azure Functions 内での一意性を確保するために検証されます。ランタイム スタックを選択してください Node.js 18 LTS 以上の最新バージョンを選択します。 OS を選択する [ Linux] を選択します。 Select a resource group for new resources (新しいリソース用のリソース グループを選択してください) azure-tutorial-first-function という名前の新しいリソース グループを作成します。 このリソース グループには、最終的に Azure Function、Azure Storage、Cosmos DB for MongoDB API という複数のリソースが含まれます。 ホスティング プランを選択する [ 従量課金] を選択します。 ストレージ アカウントを選んでください [ 新しいストレージ アカウントの作成] を 選択し、既定の名前をそのまま使用します。 アプリの Application Insights リソースを選択します。 [ 新しい Application Insights リソースの作成] を 選択し、既定の名前をそのまま使用します。 通知がアプリが作成されたことを確認するまで待ちます。
7. Visual Studio Code で Azure 関数アプリを Azure にデプロイする
重要
既存の関数アプリにデプロイすると、Azure にあるそのアプリの内容が常に上書きされます。
- アクティビティ バーの [Azure] アイコンを選択し、[ リソース ] 領域で関数アプリ リソースを右クリックし、[ 関数アプリにデプロイ] を選択します。
- デプロイするかどうかを確認するメッセージが表示されたら、[デプロイ] を選択します。
- デプロイが完了すると、いくつかのオプションを含む通知が表示されます。 [出力の表示] を選択して、結果を表示します。 通知を見逃した場合は、右下隅にあるベル アイコンを選択して、再度確認します。
8. クラウド アプリにアプリケーション設定を追加する
アクティビティ バーで Azure アイコンを選択し、[ リソース ] 領域で関数アプリ リソースを展開し、[ アプリケーション設定] を右クリックします。
[ 新しい設定の追加] を 選択し、次の設定を追加して、Node.js v4 (プレビュー) プログラミング モデルを有効にします。
設定 [値] AzureWebJobsFeatureFlags EnableWorkerIndexing
9. リモート サーバーレス関数を実行する
Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
[リソース] セクションで、Azure Function App リソースを展開します。 関数名を右クリックし、[関数 URL のコピー] を選択します。
URL をブラウザーに貼り付けます。 関数をローカルで実行したときと同じ空の配列が返されます。
{"blogposts":[]}
10. Azure Cosmos DB for MongoDB API 統合を追加する
Azure Cosmos DB には、使い慣れた統合ポイントを提供する MongoDB API が用意されています。
Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
[リソース]セクションで、+ を選択し、[データベースサーバーの作成] を選択します。 次の表を使用して、新しい Azure Cosmos DB リソースを作成するためのプロンプトを完了します。
Prompt 値 メモ Azure データベース サーバーを選択してください Azure Cosmos DB for MongoDB API Azure Cosmos DB アカウント名を指定します。 cosmosdb-mongodb-database
3 文字をポストペンして一意の名前を作成します。 この名前は、API の URL の一部になります。 容量モデルを選択してください。 サーバーレス 新しいリソース用のリソース グループを選択してください azure-tutorial-first-function 前のセクションで作成したリソース グループを選択します。 新しいリソースの場所の選択。 推奨されるリージョンを選びます。
11. mongoose 依存関係をインストールする
Visual Studio Code のターミナルで、Ctrl + Shift + ` キーを押し、npm パッケージをインストールします。
npm install mongoose
12. ブログ投稿用の mongoose コードを追加する
Visual Studio Code で、 で
./src/
lib という名前のサブディレクトリを作成し、 という名前./database.ts
のファイルを作成し、そこに次のコードをコピーします。import { Schema, Document, createConnection, ConnectOptions, model, set } from 'mongoose'; const connectionString = process.env.MONGODB_URI; console.log('connectionString', connectionString); const connection = createConnection(connectionString, { useNewUrlParser: true, useUnifiedTopology: true, autoIndex: true } as ConnectOptions); export interface IBlogPost { author: string title: string body: string } export interface IBlogPostDocument extends IBlogPost, Document { id: string created: Date } const BlogPostSchema = new Schema({ id: Schema.Types.ObjectId, author: String, title: String, body: String, created: { type: Date, default: Date.now } }); BlogPostSchema.set('toJSON', { transform: function (doc, ret, options) { ret.id = ret._id; delete ret._id; delete ret.__v; } }); export const BlogPost = model<IBlogPostDocument>('BlogPost', BlogPostSchema); connection.model('BlogPost', BlogPostSchema); export default connection;
Visual Studio Code で、
./src/functions/blogposts
ファイルを開き、ファイルのコード全体を次で置き換えます。import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions"; import connection from '../lib/database'; // curl --location 'http://localhost:7071/api/blogposts' --verbose export async function getBlogPosts(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> { context.log(`Http function getBlogPosts processed request for url "${request.url}"`); const blogposts = await connection.model('BlogPost').find({}); return { status: 200, jsonBody: { blogposts } }; }; app.get('getBlogPosts', { route: "blogposts", authLevel: 'anonymous', handler: getBlogPosts });
13. ローカル アプリに接続文字列を追加する
Visual Studio Code の Azure エクスプローラーで、[ Azure Cosmos DB ] セクションを選択し、 を展開して新しいリソースを右クリックして選択します。
[ 接続文字列のコピー] を選択します。
Visual Studio Code で、エクスプローラーを使用して を開きます
./local.settings.json
。という名前
MONGODB_URI
の新しいプロパティを追加し、接続文字列の値を貼り付けます。{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "", "FUNCTIONS_WORKER_RUNTIME": "node", "AzureWebJobsFeatureFlags": "EnableWorkerIndexing", "MONGODB_URI": "mongodb://...." } }
ファイル内
./local.settings.json
のシークレット:- ファイルに含まれているため、Azure に
./.funcignore
デプロイされません。 - ファイルに含まれているため、ソース管理に
./.gitignore
チェックインされません。
- ファイルに含まれているため、Azure に
アプリケーションをローカルで実行し、前のセクションと同じ URL で API をテストします。
14. リモート アプリに接続文字列を追加する
- Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
- [ リソース ] セクションで、Azure Cosmos DB インスタンスを見つけます。 リソースを右クリックし、[接続文字列のコピー] を選択します。
- 同じ [リソース] セクションで、関数アプリを見つけてノードを展開します。
- [アプリケーションの設定] を右クリックし、 [Add New Setting](新しい設定の追加) を選択します。
- アプリ設定名を入力し、
MONGODB_URI
Enter キーを押します。 - コピーした値を貼り付け、Enter キーを押します。
15. ブログ投稿の作成、更新、削除のための API を追加する
Visual Studio Code でコマンド パレットを使用して、[Azure Functions: 関数の作成] を見つけて選択します。
[ HTTP トリガー ] を選択し、それに名前を付けます
blogpost
(単数)。ファイルに次のコードをコピーします。
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions"; import connection, { IBlogPost, IBlogPostDocument } from '../lib/database'; // curl -X POST --location 'http://localhost:7071/api/blogpost' --header 'Content-Type: application/json' --data '{"author":"john","title":"my first post", "body":"learn serverless node.js"}' --verbose export async function addBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> { context.log(`Http function addBlogPost processed request for url "${request.url}"`); const body = await request.json() as IBlogPost; const blogPostResult = await connection.model('BlogPost').create({ author: body?.author, title: body?.title, body: body?.body }); return { status: 200, jsonBody: { blogPostResult } }; }; // curl -X PUT --location 'http://localhost:7071/api/blogpost/64568e727f7d11e09eab473c' --header 'Content-Type: application/json' --data '{"author":"john jones","title":"my first serverless post", "body":"Learn serverless Node.js with Azure Functions"}' --verbose export async function updateBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> { context.log(`Http function updateBlogPost processed request for url "${request.url}"`); const body = await request.json() as IBlogPost; const id = request.params.id; const blogPostResult = await connection.model('BlogPost').updateOne({ _id: id }, { author: body?.author, title: body?.title, body: body?.body }); if(blogPostResult.matchedCount === 0) { return { status: 404, jsonBody: { message: 'Blog post not found' } }; } return { status: 200, jsonBody: { blogPostResult } }; }; // curl --location 'http://localhost:7071/api/blogpost/6456597918547e37d515bda3' --verbose export async function getBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> { context.log(`Http function getBlogPosts processed request for url "${request.url}"`); console.log('request.params.id', request.params.id) const id = request.params.id; const blogPost = await connection.model('BlogPost').findOne({ _id: id }); if(!blogPost) { return { status: 404, jsonBody: { message: 'Blog post not found' } }; } return { status: 200, jsonBody: { blogPost } }; }; // curl --location 'http://localhost:7071/api/blogpost/6456597918547e37d515bda3' --request DELETE --header 'Content-Type: application/json' --verbose export async function deleteBlogPost(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> { context.log(`Http function deleteBlogPost processed request for url "${request.url}"`); const id = request.params.id; const blogPostResult = await connection.model('BlogPost').deleteOne({ _id: id }); if(blogPostResult.deletedCount === 0) { return { status: 404, jsonBody: { message: 'Blog post not found' } }; } return { status: 200, jsonBody: { blogPostResult } }; }; app.get('getBlogPost', { route: "blogpost/{id}", authLevel: 'anonymous', handler: getBlogPost }); app.post('postBlogPost', { route: "blogpost", authLevel: 'anonymous', handler: addBlogPost }); app.put('putBlogPost', { route: "blogpost/{id}", authLevel: 'anonymous', handler: updateBlogPost }); app.deleteRequest('deleteBlogPost', { route: "blogpost/{id}", authLevel: 'anonymous', handler: deleteBlogPost });
デバッガーでローカル関数をもう一度起動します。 次の API を使用できます。
deleteBlogPost: [DELETE] http://localhost:7071/api/blogpost/{id} getBlogPost: [GET] http://localhost:7071/api/blogpost/{id} getBlogPosts: [GET] http://localhost:7071/api/blogposts postBlogPost: [POST] http://localhost:7071/api/blogpost putBlogPost: [PUT] http://localhost:7071/api/blogpost/{id}
cURL コマンドの
blogpost
(単数形) API を使用して、いくつかのブログ投稿を追加します。curl -X POST --location 'http://localhost:7071/api/blogpost' --header 'Content-Type: application/json' --data '{"author":"john","title":"my first post", "body":"learn serverless node.js"}' --verbose
blogposts
cURL コマンドの (複数形) API を使用して、ブログの投稿を取得します。curl http://localhost:7071/api/blogposts --verbose
16. Azure Cosmos DB の Visual Studio Code 拡張機能を使用してすべてのデータを表示する
Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
[ リソース ] セクションで、Azure Cosmos DB データベースを右クリックし、[ 更新] を選択します。
テスト データベースと blogposts コレクション ノードを展開してドキュメントを表示します。
一覧表示されている項目のいずれかを選択して、Azure Cosmos DB インスタンスのデータを表示します。
17. データベース コードを含むように関数アプリを再デプロイする
- Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
- [リソース] セクションで、Azure 関数アプリを右クリックし、[関数アプリにデプロイする] を選択します。
- デプロイするかどうかを尋ねるポップアップで、 [デプロイ] を選択します。
- デプロイが完了するまで待ってから続行します。
18. クラウドベースの Azure 関数を使用する
- 引き続き Azure エクスプローラーの [Functions] 領域で、関数を選択して展開し、[Functions] ノードに API を一覧表示します。
- いずれかの API を右クリックし、[関数 URL の コピー] を選択します。
- 前のcURLコマンドを編集して、ローカル URL ではなくリモート URLを使用します。 コマンドを実行してリモート API をテストします。
19. Azure 関数ログに対してクエリを実行する
ログを検索するには、Azure portal を使用します。
Visual Studio Code で、Azure Explorer を選択して、[Functions](関数) で関数アプリを右クリックし、[ポータルで開く] を選択します。
これにより、Azure portal が開き、Azure 関数が表示されます。
[設定] の [Application Insights] を選択し、[Application Insights データの表示] を選択します。
このリンクを使用すると、Visual Studio Code で Azure 関数を作成したときに作成された個別のメトリック リソースに移動します。
[監視] セクションで、[ログ] を選択します。 [クエリ] ポップアップ ウィンドウが表示された場合、ポップアップの右上隅にある [X] を選択して閉じます。
[新しいクエリ 1] ペインの [テーブル] タブで、 [traces] テーブルをダブルクリックします。
これにより Kusto クエリの
traces
がクエリ ウィンドウに入力されます。クエリを編集して、カスタム ログを検索します。
traces | where message startswith "***"
[実行] を選択します。
ログに結果が表示されない場合、Azure 関数への HTTP 要求から Kusto でログが利用できるようになるまでに数分の遅延があることが原因となる場合があります。 数分待って、クエリを再度実行します。
このログ情報を取得するために、追加の操作を行う必要はありませんでした。
- このコードでは、関数フレームワークによって提供される
context.log
関数が使用されました。console
の代わりに、context
を使用することで、ログを特定の個々の関数にフィルター処理できます。 これは、関数アプリに多数の関数がある場合に役立ちます。 - 関数アプリによって、"ユーザー用" の Application Insights が追加されました。
- Kusto クエリ ツールは、Azure portal に含まれています。
- Kusto クエリ を記述してログから最小情報を取得する方法について学習する必要はなく、代わりに
traces
を選択することができます。
- このコードでは、関数フレームワークによって提供される
20. リソースをクリーンアップする
1 つのリソース グループを使用したため、リソース グループを削除することですべてのリソースを削除できます。
- Visual Studio Code で Azure エクスプローラーを開きます。プライマリ サイド バーで Azure アイコンを選択するか、キーボード ショートカット (Shift + Alt + A) を使用します。
- [Azure: リソース グループ別にグループ化] を検索して選択します。
- 右クリックしてリソース グループを選択し、[リソース グループの削除] を選択 します。
- リソース グループ名を入力して削除を確認します。
利用可能なソース コード
この Azure 関数アプリの完全なソースコード:
次のステップ
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示