共用方式為


教學課程:使用 TypeScript 和 MongoDB 建置無伺服器 API

在本教學課程中,您將瞭解如何使用 Azure Functions 和 TypeScript 建立無伺服器 API,以將數據儲存在 MongoDB 中。 我們將引導您將應用程式部署至 Azure,使其可透過公用 HTTP 端點存取。

必要條件

安裝下列軟體:

解決方案架構

解決方案會使用 Azure Functions 應用程式來接收數據,然後從 Mongoose SDK 傳送至 Azure Cosmos DB。

流程圖顯示 HTTP 要求的路徑,以透過 Azure Functions 傳遞數據,並儲存在 Azure Cosmos DB 中。

開啟開發環境

  1. 在終端機或命令提示字元中,於本機系統上建立新資料夾,以作為 Azure Functions 專案的根目錄。

    mkdir <YOUR-NEW_FOLDER-NAME>
    
  2. 變更為新的資料夾。

    cd <YOUR-NEW_FOLDER-NAME>
    
  3. 在 Visual Studio Code 中開啟此資料夾。

    code .
    

在 Visual Studio Code 中登入 Azure

  1. 開啟命令選擇區。
  2. 搜尋並選取 Azure: Sign in。 完成向 Azure 驗證的步驟。

建立 Azure 資源群組

資源群組是以區域為基礎的資源集合。 藉由建立資源群組,然後在該群組中建立資源,在教學課程結束時,您可以刪除資源群組,而不需要個別刪除每個資源。

  1. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。

  2. 在 [資源] 下尋找您的訂用帳戶,+然後選取圖示,然後選取 [建立資源群組]。

  3. 使用下表完成提示:

    提示
    輸入新資源群組的名稱。 azure-tutorial
    選取新資源的位置。 選取靠近您的地理區域。

建立本機 Functions 應用程式

建立包含 HTTP 觸發程式函式的本機 Azure Functions(無伺服器)應用程式。

  1. 在 Visual Studio Code 中,開啟命令選擇區 (Ctrl + Shift + P)。

  2. 搜尋並選取 [Azure Functions:建立新專案 ]。

  3. 使用下表完成建立本機 Azure 函式專案:

    提示 備註
    選取將包含函式項目的資料夾 選取目前 (預設) 資料夾。
    選取語言 TypeScript
    選取 TypeScript 程式設計模型 模型 V4
    為您專案的第一個函式選取範本 HTTP 觸發程序 使用 HTTP 要求叫用 API。
    提供函式名稱 blogposts API 路由為 /api/blogposts
  4. 當 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 層的唯一方法。

  5. 將先前的程式代碼取代為下列程式代碼,只允許 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 要求。

啟動 Azurite 本機記憶體模擬器

在您的本機計算機上開發函式需要記憶體模擬器(免費)或 Azure 儲存體 帳戶(付費)。

  1. 在不同的終端機中 ,啟動 Azurite 本機記憶體模擬器。

    azurite --silent --location ./azurite --debug ./azurite/debug.log
    

    這是使用本機 Azure 儲存體 模擬器在本機執行 Azure Functions 的必要專案。

  2. 使用 AzureWebJobsStorage 屬性將檔案中指定的local.settings.json本機記憶體模擬器更新為 的值UseDevelopmentStorage=true

    {
        "IsEncrypted": false,
        "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "node",
        "AzureWebJobsFeatureFlags": "EnableWorkerIndexing"
        }
    }
    

執行本機無伺服器函式

在本機執行 Azure Functions 專案,以在部署至 Azure 之前進行測試。

  1. 在 Visual Studio Code 中,於 getBlogPosts 函式結尾的 語句上return設定斷點。

  2. 在 Visual Studio Code 中,按 F5 啟動調試程式並附加至 Azure Functions 主機。 如果系統提示您,請啟用公用和私人端點。

    您也可以使用 [偵錯>開始偵錯] 功能表命令。

  3. 輸出會出現在 終端 機面板中。

  4. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。

  5. 在 [工作區] 區段中,尋找並展開 [本機專案 - Functions ->> getBlogPosts]。

  6. 以滑鼠右鍵按下函式名稱 getBlogPosts,然後選取 [複製函式 URL]。

    Visual Studio Code 的部分螢幕快照,其中醒目提示了名為 [複製函式 URL] 的 Azure 函式按鈕。

  7. 在您的瀏覽器中,貼上並提交URL。

    或者,您可以在終端機中使用下列 cURL 命令:

    curl http://localhost:7071/api/blogposts --verbose
    
  8. 當調試程式在 Visual Studio Code 中停止時,您可以在 Variables-Local> 視窗中看到空白的部落格文章。 允許偵錯再次按 F5 以繼續超過該斷點。

  9. 空的部落格文章陣列回應會傳回為:

    {
        "blogposts": []
    }
    
  10. 在 VS Code 中,停止調試程式 Shift + F5。

在 Visual Studio Code 中建立 Azure 函式應用程式

在本節中,您會在 Azure 訂用帳戶中建立函式應用程式雲端資源和相關資源。

  1. 在 Visual Studio Code 中,開啟命令選擇區 (Ctrl + Shift + P)。

  2. 搜尋並選取 Azure Functions:在 Azure 中建立函式應用程式 (進階)

  3. 提示中會提供下列資訊:

    提示 選取項目
    選取訂用帳戶 選取您的計費訂閱。
    輸入函數應用程式的全域唯一名稱 輸入 URL 路徑中有效的名稱,例如 first-function。 Postpend 3 個字元,讓 URL 成為全域唯一的。 您鍵入的名稱會經過驗證,確定其在 Azure Functions 中是唯一。
    選取主控方案 選擇 [ 取用]。
    選取新資源的位置 選取您附近的地理位置。
    選取執行階段堆疊 選擇最新的 LTS 版本。
    選取OS 選擇 [Linux]。
    選取主控方案 選擇 [ 取用]。
    選取新資源的資源群組 選取您在上一個步驟中建立的資源群組
    選取儲存體帳戶 選取 [建立新的記憶體帳戶 ],並接受預設名稱。
    選取應用程式的 Application Insights 資源。 選取 [建立新的 Application Insights 資源 ],並接受預設名稱。

    等候通知確認應用程式已建立。

在 Visual Studio Code 中將 Azure 函式應用程式部署至 Azure

重要

部署至現有的函數應用程式一律會覆寫該應用程式在 Azure 中的內容。

  1. 選擇活動列中的 Azure 圖示,然後在 [資源] 區域中,以滑鼠右鍵按兩下您的函式應用程式資源,然後選取 [部署至函式應用程式]。
  2. 如果系統詢問您是否確定要部署,請選取 [部署]。
  3. 部署完成之後,通知會顯示數個選項。 選取 [ 檢視輸出 ] 以檢視結果。 如果您錯過通知,請選取右下角的鈴鐺圖示,以再次查看。

執行遠端無伺服器函式

  1. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。

  2. 在 [資源]段中,展開您的 Azure 函式應用程式資源。 以滑鼠右鍵按下函式名稱,然後選取 [ 複製函式 URL]。

  3. 將 URL 貼到瀏覽器中。 當您在本機執行函式時,會傳回相同的空陣列。

    {"blogposts":[]}
    

新增適用於 MongoDB API 整合的 Azure Cosmos DB

Azure Cosmos DB 提供 MongoDB API,以提供熟悉的整合點。

  1. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。

  2. 在 [ 資源] 區段中,選取 + ,然後選取 [ 建立資料庫伺服器]。 使用下表完成建立新 Azure Cosmos DB 資源的提示。

    提示 備註
    選取 Azure 資料庫伺服器 適用於 MongoDB 的 Azure Cosmos DB API
    提供 Azure Cosmos DB 帳戶名稱。 cosmosdb-mongodb-database 加上三個字元以建立唯一的名稱。 名稱會成為 API URL 的一部分。
    定義容量模型。 Serverless
    選取 [MongoDB 版本]。 選取最新版本。
    選取新資源的資源群組。 選取您在上一個步驟中建立的資源群組 選取您在上一節中建立的資源群組。
  3. 等候建立資源。 您可以在結果窗格的 [Azure] 區段中看到狀態

安裝mongoose相依性

在 Visual Studio Code 終端機中,Ctrl + Shift + `,然後安裝 npm 套件:

npm install mongoose

新增部落格文章的mongoose程式代碼

  1. 在 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;
    
  2. 在 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
    });
    

將 連接字串 新增至本機應用程式

  1. 在 Visual Studio Code 的 Azure 總管中,選取 [Azure Cosmos DB ] 區段,然後展開以滑鼠右鍵按下選取您的新資源。

  2. 選取 [複製 連接字串]。

  3. 在 Visual Studio Code 中,使用 [檔案總管] 開啟 ./local.settings.json

  4. 新增名為 MONGODB_URI 的新屬性,並貼上 連接字串的值。

    {
      "IsEncrypted": false,
      "Values": {
        "AzureWebJobsStorage": "",
        "FUNCTIONS_WORKER_RUNTIME": "node",
        "AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
        "MONGODB_URI": "mongodb://...."
      }
    }
    

    檔案中的 ./local.settings.json 秘密:

    • 不會部署至 Azure,因為它包含在檔案中 ./.funcignore
    • 不會簽入原始檔控制,因為它包含在檔案中 ./.gitignore

將 連接字串 新增至遠端應用程式

  1. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
  2. 在 [資源]段中,尋找您的 Azure Cosmos DB 實例。 以滑鼠右鍵按兩下資源,然後選取 [ 複製連接字串]。
  3. 在相同的 [資源] 區段中,尋找您的函式應用程式並展開節點。
  4. 以滑鼠右鍵按兩下 [ 應用程式設定 ],然後選取 [ 新增設定]。
  5. 輸入應用程式設定名稱, MONGODB_URI 然後選取 Enter。
  6. 貼上您複製的值,然後按 Enter 鍵。

新增用於建立、更新和刪除部落格文章的 API

  1. 在 Visual Studio Code 中,使用命令選擇區來尋找並選取 [Azure Functions:建立函式]。

  2. 選取 [HTTP 觸發程式 ] 並將其 blogpost 命名為 [單一]。

  3. 將下列程式碼複製至 檔案。

    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
    });
    
  4. 再次使用調試程序啟動本機函式。 下列 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}
    
  5. 使用 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
    
  6. 使用 cURL 命令中的 blogposts (plural) API 來取得部落格文章。

    curl http://localhost:7071/api/blogposts --verbose
    
  7. 回應包含單一部落格文章的 JSON 陣列: :[{"author":"john","title":"my first post","body":"learn serverless node.js","created":"2024-07-11T21:30:41.688Z","id":"66904f0148b2e4d8a2b9971e"}]}

使用適用於 Azure Cosmos DB 的 Visual Studio Code 擴充功能檢視所有數據

  1. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。

  2. 在 [資源] 區段中,以滑鼠右鍵按兩下您的 Azure Cosmos DB 資料庫,然後選取 [重新整理]。

  3. 展開測試資料庫和部落格文章集合節點,以檢視檔。

  4. 選取其中一個專案,以檢視 Azure Cosmos DB 實例中的數據。

    Visual Studio Code 的部分螢幕快照,其中顯示 Azure 檔案總管,其中包含讀取窗格中所顯示選取項目的資料庫。

重新部署函式應用程式以包含資料庫程序代碼

  1. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
  2. 在 [資源] 區段中,以滑鼠右鍵按下您的 Azure 函式應用程式,然後選取 [部署至函式應用程式]。
  3. 在彈出視窗中,詢問您是否確定要部署,請選取 [ 部署]。
  4. 等到部署完成再繼續。

使用雲端式 Azure 函式

  1. 仍在 Azure 檔案總管的 [函式] 區域中,選取並展開您的函式,然後 選取 [函 式] 節點,其中會列出 API
  2. 以滑鼠右鍵按兩下其中一個 API,然後選取 [ 複製函式 URL]。
  3. 編輯先前的 cURL 命令,以使用遠端 URL,而不是本機 URL。 執行命令以測試遠端 API。

查詢您的 Azure 函式記錄

若要搜尋記錄,請使用 Azure 入口網站。

  1. 在 Visual Studio Code 中,選取 [Azure 總管],然後在 [函式] 底下,以滑鼠右鍵按兩下您的函式應用程式,然後選取 [在入口網站中開啟]。

    這會開啟 Azure 函式 Azure 入口網站。

  2. [設定] 中,選取 [Application Insights],然後選取 [ 檢視 Application Insights 數據]。

    此連結會帶您前往使用 Visual Studio Code 建立 Azure 函式時為您建立的個別計量資源。

  3. 從 [監視]段中,選取 [記錄]。 選取 快顯右上角的 X 以關閉任何彈出視窗。

  4. 在 [新增查詢 1] 窗格中的 [數據表] 索引卷標上,按兩下追蹤數據表。

    這會在查詢視窗中輸入 Kusto 查詢traces

  5. 將查詢模式從 簡單模式 變更為 KQL 模式

  6. 編輯查詢以搜尋自訂記錄:

    traces 
    | where message startswith "***"
    
  7. 選取執行

    如果記錄檔未顯示任何結果,可能是因為 HTTP 要求與 Azure Function 與 Kusto 中的記錄可用性之間有幾分鐘的延遲。 請稍候幾分鐘,然後再次執行查詢。

    您不需要執行任何額外動作,即可取得此記錄資訊:

    • 程序代碼使用 context.log Function 架構所提供的函式。 藉由使用 context,而不是 console,您可以將記錄篩選為特定的個別函式。 如果您的函式應用程式有許多函式,這會很有用。
    • 函式應用程式已為您新增ApplicationInsights
    • Kusto 查詢工具包含在 Azure 入口網站 中。
    • 您可以選取 traces ,而不必學習撰寫 Kusto 查詢 ,以從您的記錄取得最低資訊。

可用的原始程式碼

此 Azure 函式應用程式的完整原始碼:

清除資源

因為您使用了單一資源群組,因此您可以藉由刪除資源群組來刪除所有資源。

  1. 在 Visual Studio Code 中,選取主要側邊列中的 Azure 圖示或使用鍵盤快捷方式 (Shift + Alt + A) 來開啟 Azure 總管。
  2. 搜尋並選取 [Azure:依資源群組分組]。
  3. 以滑鼠右鍵按下選取您的資源群組,然後選取 [ 刪除資源群組]。
  4. 輸入資源組名以確認刪除。

後續步驟