無伺服器 TypeScript API:使用 Azure Functions 將資料儲存在 MongoDB 中
建立 Azure 函式 API,以使用 Mongoose API 將資料儲存至 Azure Cosmos DB,然後將函式應用程式部署至 Azure 雲端,以使用公用 HTTP 端點裝載。
注意
本文使用目前處於預覽狀態的 Azure Functions Node.js v4 程序設計模型 。
準備您的開發環境
安裝下列軟體:
- 建立免費的 Azure 訂用帳戶
- 安裝 Node.js LTS v18+
- TypeScript v4+
- 針對本機開發記憶體全域安裝的 Azurite
- Azure Functions 運行時間 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 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
在 [資源] 區段中,選取 [登入 Azure],然後遵循提示。
登入之後,請確認 Azure 帳戶的電子郵件地址會出現在狀態列,而您的訂用帳戶出現在 Azure 總管中:
2.建立 Azure 資源群組
資源群組是以區域為基礎的資源集合。 藉由建立資源群組,然後在該群組中建立資源,在教學課程結束時,您可以刪除資源群組,而不需要個別刪除每個資源。
在您的本機系統上建立新資料夾,以作為 Azure Functions 專案的根目錄。
在 Visual Studio Code 中開啟此資料夾。
在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
在 [資源] 下尋找您的訂用帳戶,+然後選取圖示,然後選取 [建立資源群組]。
使用下表完成提示:
提示 值 輸入新資源群組的名稱。 azure-tutorial
選取新資源的位置。 選取靠近您的地理區域。
3.建立本機 Functions 應用程式
建立包含 HTTP 觸發程式函式的本機 Azure Functions(無伺服器)應用程式。
在 Visual Studio Code 中,開啟命令選擇區 (Ctrl + Shift + P)。
搜尋並選取 [Azure Functions:建立新專案 ]。
使用下表完成建立本機 Azure 函式專案:
提示 值 備註 選取將包含函式項目的資料夾 選取目前 (預設) 資料夾。 選取語言 TypeScript 選取 TypeScript 程式設計模型 模型 V4 (預覽) 為您專案的第一個函式選取範本 HTTP 觸發程序 使用 HTTP 要求叫用 API。 提供函式名稱 blogposts
API 路由為 /api/blogposts
當 Visual Studio Code 建立專案時,請在 檔案中
./src/functions/blogposts.ts
檢視您的 API 程式代碼。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 });
您應該注意下列程式代碼的數個 Azure Functions Node.js v4 程式設計模型變更 :
- 的函式名稱
getBlobPosts
,表示它是 GET 要求,將協助您隔離記錄中的函式。 - 屬性
route
設定為blogposts
,這是提供/api/blogposts
的預設 API 路由的一部分。 - 屬性
methods
已移除,而且不必要,因為app
物件的使用get
表示這是 GET 要求。 方法函式如下所列。 如果您有不同的方法,則可以使用methods
屬性傳回 。deleteRequest()
get()
patch()
post()
put()
- 的函式名稱
4.啟動 Azurite 本機記憶體模擬器
在您的本機計算機上開發函式需要 儲存體 模擬器(免費)或 Azure 儲存體 帳戶(付費)。
在不同的終端機中 ,啟動 Azurite 本機記憶體模擬器。
azurite --silent --location ./azurite --debug ./azurite/debug.log
這是使用本機 Azure 儲存體 模擬器在本機執行 Azure Functions 的必要專案。 本機記憶體模擬器是使用 AzureWebJobs 儲存體 屬性在 檔案中local.settings.json
指定,其值為 UseDevelopmentStorage=true
。
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "node",
"AzureWebJobsFeatureFlags": "EnableWorkerIndexing"
}
}
子 azurite
資料夾已新增至您的 .gitignore
檔案。
5.執行本機無伺服器函式
在本機執行 Azure Functions 專案,以在部署至 Azure 之前進行測試。
在 Visual Studio Code 中,於 getBlogPosts 函式結尾的 語句上
return
設定斷點。在 Visual Studio Code 中,按 F5 啟動調試程式並附加至 Azure Functions 主機。
您也可以使用 [偵錯>開始偵錯] 功能表命令。
輸出會出現在 終端 機面板中。
在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
在 [工作區] 區段中,尋找並展開 [本機專案 - 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 中建立函式應用程式 (進階) 。
提示中會提供下列資訊:
提示 選取項目 輸入函式應用程式的全域唯一名稱 輸入 URL 路徑中有效的名稱,例如 first-function
。 Postpend 3 個字元,讓 URL 成為全域唯一的。 您鍵入的名稱會經過驗證,確定其在 Azure Functions 中是唯一。選取運行時間堆疊 選擇 Node.js 18 LTS 或較新版本。 選取OS 選擇 [Linux]。 選取新資源的資源群組 建立名為 azure-tutorial-first-function 的新資源群組。 此資源群組最終會有數個資源:Azure 函式、Azure 儲存體 和適用於 MongoDB 的 Cosmos DB 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 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
在 [資源] 區段中,展開您的 Azure 函式應用程式資源。 以滑鼠右鍵按下函式名稱,然後選取 [ 複製函式 URL]。
將 URL 貼到瀏覽器中。 當您在本機執行函式時,會傳回相同的空陣列。
{"blogposts":[]}
10.新增適用於 MongoDB API 整合的 Azure Cosmos DB
Azure Cosmos DB 提供 MongoDB API,以提供熟悉的整合點。
在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
在 [ 資源] 區段中,選取 + ,然後選取 [ 建立資料庫伺服器]。 使用下表完成建立新 Azure Cosmos DB 資源的提示。
提示 值 備註 選取 Azure 資料庫伺服器 適用於 MongoDB 的 Azure Cosmos DB API 提供 Azure Cosmos DB 帳戶名稱。 cosmosdb-mongodb-database
加上三個字元以建立唯一的名稱。 名稱會成為 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 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
- 在 [資源] 區段中,尋找您的 Azure Cosmos DB 實例。 以滑鼠右鍵按兩下資源,然後選取 [複製 連線 ion 字串]。
- 在相同的 [資源] 區段中,尋找您的函式應用程式並展開節點。
- 以滑鼠右鍵按兩下 [應用程式] 設定,然後選取 [新增設定]。
- 輸入應用程式設定名稱,
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
使用 cURL 命令中的
blogposts
(plural) API 來取得部落格文章。curl http://localhost:7071/api/blogposts --verbose
16.使用適用於 Azure Cosmos DB 的 Visual Studio Code 擴充功能檢視所有數據
在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
在 [資源] 區段中,以滑鼠右鍵按兩下您的 Azure Cosmos DB 資料庫,然後選取 [重新整理]。
展開測試資料庫和部落格文章集合節點,以檢視檔。
選取其中一個專案,以檢視 Azure Cosmos DB 實例中的數據。
17.重新部署函式應用程式以包含資料庫程序代碼
- 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
- 在 [資源] 區段中,以滑鼠右鍵按下您的 Azure 函式應用程式,然後選取 [部署至函式應用程式]。
- 在彈出視窗中,詢問您是否確定要部署,請選取 [ 部署]。
- 等到部署完成再繼續。
18.使用雲端式 Azure 函式
- 仍在 Azure 檔案總管的 [函式] 區域中,選取並展開您的函式,然後 選取 [函 式] 節點,其中會列出 API
- 以滑鼠右鍵按兩下其中一個 API,然後選取 [ 複製函式 URL]。
- 編輯先前的 cURL 命令,以使用遠端 URL,而不是本機 URL。 執行命令以測試遠端 API。
19.查詢您的 Azure 函式記錄
若要搜尋記錄,請使用 Azure 入口網站。
在 Visual Studio Code 中,選取 [Azure 總管],然後在 [函式] 底下,以滑鼠右鍵按兩下您的函式應用程式,然後選取 [在入口網站中開啟]。
這會開啟 Azure 函式 Azure 入口網站。
從 設定 選取 [Application Insights],然後選取 [檢視 Application Insights 數據]。
此連結會帶您前往使用 Visual Studio Code 建立 Azure 函式時為您建立的個別計量資源。
從 [監視] 區段中,選取 [記錄]。 如果出現 [ 查詢 ] 彈出視窗,請選取 快顯右上角的 X 以關閉它。
在 [新增查詢 1] 窗格中的 [數據表] 索引卷標上,按兩下追蹤數據表。
這會在查詢視窗中輸入 Kusto 查詢
traces
。編輯查詢以搜尋自訂記錄:
traces | where message startswith "***"
選取執行。
如果記錄檔未顯示任何結果,可能是因為 HTTP 要求與 Azure Function 與 Kusto 中的記錄可用性之間有幾分鐘的延遲。 請稍候幾分鐘,然後再次執行查詢。
您不需要執行任何額外動作,即可取得此記錄資訊:
- 程序代碼使用
context.log
Function 架構所提供的函式。 藉由使用context
,而不是console
,您可以將記錄篩選為特定的個別函式。 如果您的函式應用程式有許多函式,這會很有用。 - 函式應用程式已為您新增ApplicationInsights。
- Kusto 查詢工具包含在 Azure 入口網站 中。
- 您可以選取
traces
,而不必學習撰寫 Kusto 查詢 ,以從您的記錄取得最低資訊。
- 程序代碼使用
20.清除資源
因為您使用了單一資源群組,因此您可以藉由刪除資源群組來刪除所有資源。
- 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
- 搜尋並選取 [Azure:依資源群組分組]。
- 以滑鼠右鍵按下選取您的資源群組,然後選取 [ 刪除資源群組]。
- 輸入資源組名以確認刪除。
可用的原始程式碼
此 Azure 函式應用程式的完整原始碼:
下一步
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應