练习 - 为 Azure Functions 应用创建函数

已完成

在本单元中,你将在 Azure Functions 应用中为 Node.js Express 应用中的 GETPOSTPUTDELETE 终结点创建和配置函数。

向 GET 函数添加数据访问权限

在上一个单元中创建 Azure Functions 应用时,你创建了第一个 API 终结点。 此函数在 /vacations 上请求 HTTP GET 时执行。 你需要更新样板代码来调用数据服务以获取假期。

  1. 打开 functions/src/functions/getVacations.ts 文件。

  2. 在单独的窗口中打开 server/routes/vacation.routes.ts 文件,这样就可以并排查看这两个文件。

  3. 在 getVacations.ts 中,添加 vacationService import 语句。

    import { vacationService } from '../services';
    
  4. 在 getVacations.ts 中,编辑 getVacations 函数以调用 VacationService。

     export async function getVacations(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
         context.log(`Http function processed request for url "${request.url}"`);
         return { jsonBody: vacationService.getVacations() }; // Data access logic within the return object
     };
    
  5. 你可以停在那里。 这是唯一需要添加到函数中以获取假期的代码。 但是,你还应该提供代码来处理错误并返回状态代码。 更新该函数以使用以下代码。

     export async function getVacations(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
       context.log(`Http function processed request for url "${request.url}"`);
    
       try {
         const vacations = vacationService.getVacations();  // Data access logic
    
         if (vacations) {
           return {
             status: 200,
             jsonBody: vacations
           };
         } else {
           return {
             status: 404,
             jsonBody: {
               error: 'No vacations found'
             }
           };
         }      
       } catch (error: unknown) {
         const err = error as Error;
         context.error(`Error listing vacations: ${err.message}`);
    
         return {
           status: 500,
           jsonBody: {
             error: 'Failed to list vacations'
           }
         };
       }
     };
    

组织 Azure Functions 路由

在 v4 编程模型中,可以通过多种方式组织路由。 可以将路由定义与路由处理程序保留在单个文件中。 这适用于具有一个终结点的应用程序。 作为 Tailwind Traders 的开发人员,你知道该应用程序将开发成许多需要进行组织的 API。

  1. 若要启动该组织,请创建一个新的 ./functions/src/index.ts 文件来捕获路由定义。

  2. 添加从 @azure/functions 包提供的应用的依赖项。

    import { app } from '@azure/functions';
    
  3. 添加 ./functions/getVacations 文件中的 getVacations 函数的依赖项。

    import { getVacations } from `./functions/getVacations`;
    
  4. 将路由定义从 ./functions/getVacations 移至 index.ts 文件。 将 method 属性数组更新为 GET

    app.http('getVacations', {
        methods: ['GET'],
        route: 'vacations',
        authLevel: 'anonymous',
        handler: getVacations
    });
    

为函数和处理程序命名

名称 getVacations 既用作 app.http 的第一个参数,又用作第二个参数中的属性。 这可能会令人感到困惑,你可能希望在组织或团队中根据名称使用方式来使用不同的命名规则。

Screenshot of the http definition with the first parameter numbered as one, and the second parameter's handler property numbered as two.

  • 第一个参数 - 字符串形式的名称:第一个参数的值是函数的名称,它将显示在 Azure 门户中。 这些名称在门户中按字母数字顺序列出,因此你可能需要使用命名约定,将类似的函数按用途(例如 vacationGet)或按方法(例如 getVacation)组合在一起。 还可以选择其他大小写,例如 snake_case、kebab-case 或 camelCase。
  • 第二个参数 - 处理程序函数:第二个参数的值是在代码中导入和使用的函数处理程序的名称。 该名称应该是说明性的,并且应该与函数的用途匹配。 它可能遵循代码库中已有的函数命名约定,可以使用典型的代码一致性工具来强制执行。

创建剩余函数

Node.js Express 应用程序中共有四个终结点,你刚刚为 GET 终结点创建了函数。 现在为剩余的路由终结点创建函数。

方法 HTTP 触发器名称 路由
POST postVacation vacations
PUT updateVacation vacations/{id}
DELETE deleteVacation vacations/{id}

而 GET 和 POST 路由是相同的。 PUTDELETE 路由使用参数来标识要使用的假期。

创建 HTTP POST 函数

创建用于处理假期添加的 POST 函数。

  1. 在 Visual Studio Code 中,使用 Ctrl + Shift +P 打开命令面板,键入 Azure Functions: Create Function,然后按 Enter

  2. 选择“HTTP 触发器”作为类型,并选择“postVacation”作为名称。

  3. 将 vacationService import 语句添加到文件中。

    import { vacationService } from '../services';
    
  4. 将样板 postVacation 函数替换为以下用于数据访问和错误处理的代码。

    export async function postVacation(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`HTTP function processed request for URL: "${request.url}"`);
    
        try {
            const vacation = await request.json() as Vacation;
    
            // Validate the vacation object
            if (!vacation || typeof vacation !== 'object' || !vacation.name || !vacation.description) {
                return {
                    status: 400,
                    jsonBody: { 
                        error: 'Invalid or missing vacation data.' 
                    }
                };
            }
    
            // Data access logic
            const newVacation = vacationService.addVacation(vacation); 
    
            // Successfully added the vacation
            return {
                status: 201,
                jsonBody: newVacation
            };
        } catch (error: unknown) {
            const err = error as Error;
            context.error(`Error create vacation: ${err.message}`);
    
            return {
                status: 500,
                jsonBody: {
                    error: 'Failed to create vacation'
                }
            };
        }
    }
    

    若要读取传入假期数据,请使用 request.json() 方法。 此方法返回一个解析为请求正文中的 JSON 数据的承诺。 然后,你使用 await 关键字等待承诺解析。 as Vacation 语法是一种类型断言,它告诉 TypeScript 将结果视为 Vacation 对象。

    const vacation = await request.json() as Vacation;
    
  5. 将路线定义从 postVacation 文件移至 index.ts 文件。 将 method 属性数组更新为 POST

    app.http('post-vacation', {
        methods: ['POST'],
        route: 'vacations',
        authLevel: 'anonymous',
        handler: postVacation
    });
    

创建 HTTP PUT 函数

创建用于处理假期添加的 PUT 函数。

  1. 在 Visual Studio Code 中,使用 Ctrl + Shift + P 打开命令面板,键入 Azure Functions: Create Function,然后按 Enter

  2. 选择“HTTP 触发器”作为类型,并选择“updateVacation”作为名称。

  3. 将 vacationService import 语句添加到文件中。

    import { vacationService } from '../services';
    
  4. 将样板 updateVacation 函数替换为以下用于数据访问和错误处理的代码。

    export async function updateVacation(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
      try {
        const id = request.params.id;
        const { name, description } = await request.json() as Vacation;
    
        // Data access logic
        const updatedVacation = vacationService.updateVacation({ id, name, description });
    
        if (updatedVacation !== undefined) {
          return {
            status: 200,
            jsonBody: {
              updatedVacation
            }
          };
        } else {
          return {
            status: 404,
            jsonBody: {
              error: `Vacation with ID ${id} not found`
            }
          };
        }
      } catch (error: unknown) {
        const err = error as Error;
        context.error(`Error updating vacation: ${err.message}`);
    
        return {
          status: 500,
          jsonBody: {
            error: 'Failed to update vacation'
          }
        };
      }
    };
    

    request.params.id 属性用于从 URL 获取假期 ID。 request.json() 方法用于从请求正文获取假期数据。 as Vacation 语法是一种类型断言,它告诉 TypeScript 将结果视为 Vacation 对象。

  5. 将路线定义从 putVacation 文件移至 index.ts 文件。 将 method 属性数组更新为 PUT

    app.http('updateVacation', {
        methods: ['PUT'],
        route: 'vacations/{id}',
        authLevel: 'anonymous',
        handler: updateVacation
    });
    

创建 HTTP DELETE 函数

创建用于处理假期添加的 DELETE 函数。

  1. 在 Visual Studio Code 中,使用 Ctrl + Shift + P 打开命令面板,键入 Azure Functions: Create Function,然后按 Enter

  2. 选择“HTTP 触发器”作为类型,并选择“deleteVacation”作为名称。

  3. 将 vacationService import 添加到文件中。

    import { vacationService } from '../services';
    
  4. 将样板 deleteVacation 函数替换为以下用于数据访问和错误处理的代码。

    export async function deleteVacation(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
      context.log(`Http function processed request for url "${request.url}"`);
    
      try {
    
        const id = request.params.id;
    
        if (!id) {
          return {
            status: 400,
            jsonBody: {
              error: 'ID parameter is required'
            }
          };
        }
    
        const deletedVacation = vacationService.deleteVacation(id);
    
        if (deletedVacation) {
          return {
            status: 204,
            jsonBody: {
              deleteVacation
            }
          };
        } else {
          return {
            status: 404,
            jsonBody: {
              error: `Vacation with ID ${id} not found`
            }
          };
        }
      } catch (error: unknown) {
        const err = error as Error;
        context.error(`Error deleting vacation: ${err.message}`);
    
        return {
          status: 500,
          jsonBody: {
            error: 'Failed to delete vacation'
          }
        };
      }
    };
    

    request.params.id 属性用于从 URL 获取假期 ID。

  5. 将路线定义从 deleteVacation 文件移至 index.ts 文件。 将 method 属性数组更新为 DELETE

    app.http('deleteVacation', {
        methods: ['DELETE'],
        route: 'vacations/{id}',
        authLevel: 'anonymous',
        handler: deleteVacation
    });
    

前往下一单元,查看你创建的 Azure Functions 应用程序。