zoukankan      html  css  js  c++  java
  • 使用ASP.NET Core 3.x 构建 RESTful API P3 对外合约

    使用ASP.NET Core 3.x 构建 RESTful API P3 对外合约

    为了和RESTful API进行交互, API的消费者需要使用到三个概念.

    • 资源的标识. URL
    • HTTP方法. 如: Get,Post,Put,Delete等.
    • 有效载荷(可选),英文就是PayLoad:比如当我们想创建资源的时候,Http请求里面,通常会带有创建资源的表述,或者当获取资源时,Http响应体即(Body)中会包含对资源的表述.
    资源的命名

    在合理的API命名上,我们应该使用名词,而不是动词,动词应该通过Http方法来表达.

    例子1:

    • 需求: 我们看这样一个需求的例子:"我想获得系统里所有的用户".
    • 常见错误做法:api/getusers
    • 分析: 这句话的主要动词就是"获取",而想要获取的资源(也就是主要的名词)是"用户".
    • 正确的做法: Get api/user
    人类能读懂
    • 还是上面那个需求: "我想获的系统里所有的用户."
    • 我们可以把url设计成 api/u 或者 api/ur (这样的写法不够友好,看不懂)
    • 所以建议的做法是足够友好,并且比较简短,例如:api/users
    要体现资源的结构/关系
    • 假设如果后端API系统里面有若干种资源,而用户这个资源与其它的资源并没有直接的关系,这样的话获取用户资源的url应该是 api/users. 而不是api/products/users,也不是api/catalog/products/users,因为user和product或者catalog没有直接关系.
    • 通过id获取单个用户的url应该是:api/users/{urserId},而不是api/userid/users 这样写的好处是可以让Api具有和好的可预测性和一致性.

    例子2:

    • 需求:系统里有两类资源,公司(Company) 和员工 (Employee),现在我想获取某个公司下所有的员工.
    • 分析:使用HTTP的GET. API 的URL在设计的时候需要体现公司和员工的包含关系.
    • 常见的错误做法: Get api/employees, Get api/employees/{companyId}
    • 建议的做法: Get api/companies/{companyId}/employees

    例子3:

    • 需求:我想获取某个公司的某个员工信息.
    • 分析:使用HTTP的GET. API 的URL在设计的时候需要体现公司和员工的包含关系.
    • 常见的错误做法: Get api/employees/{employeeId}, Get api/Companies/{employeeid}等等
    • 建议的做法: Get api/Companies/{companyId}Employees/{employeeId}
    自定义查询怎么命名
    • 需求: 我想获取所有的用户信息,并要求结果是按年龄从小到达进行排序的.
    • 常见错误的做法: Get api/users/orderby/age
    • 建议的做法: Get api/users?orderby=age
    例外
    • 有一些需求总是无法满足的达到RESTful的约束.
    • 需求:"我想获取系统里所有用户的数量."
    • 妥协的做法: 例如: Get api/users/totalamountofuser

    RESTful 风格的API 比较适合于CRUD这类业务的API.

    好了下面是写代码的时间,我们打开p1中所创建的项目,并在其中创建一个Controller
    类.

    补充知识点:
    HTTP 动词 不是在 Controller 里面的方法名上体现的.
    约定: 当Controller中方法名的前缀如果是个动词如 GetCompanies 那么如果没有为此方法标注动词,那么默认就是以 [HttpGet] 的方式来请求此 Action.

    IActionResult 接口: IActionResult 接口相当于订阅了一些合约,这些合约代表了 Action 方法返回的结果.

    .Net CoreController类也会继承自ControllerBase类,他们主要的区别在与,ControllerBase类仅实现了,Controller(控制器)相关的功能,而Controller类,在拥有Controller(控制器)相关功能的基础上,还添加了对于View(视图)的支持.

    因此在编写 WebAPi 时,我们创建的控制器,继承自 ControllerBase类即可.
    在编写Mvc时,我们创建的控制器,需要继承自Controller类,因为其包含了对于view(视图)操作的实现.

    特性 [ApiController] 的介绍
    • 这个特性是应用于Controller的,但是它其实并不是强制要使用的.
    • 使用 [ApiController] 会启用一下行为:
      • 要求使用属性路由(Attribute Routing)
      • 自动HTTP 400 响应. (在Action方法被传入model的时候,会有一个验证动作,model含有验证错误的信息,会自动触发HTTP 400 相应.)
      • 推断参数的绑定源 (自动推断Action方法的参数到底来自于哪一个绑定源,比如:[FromBody],[FromServices]等等).
      • Multipart/Form-data 请求推断.
      • 错误状态代码的问题详细信息.
    • 使用了 [ApiController] 特性之后,我们就不能在Startup.cs类的Configure方法中的端点中间件中统一配置路由模板了,需要我们在每个 Controller 以及每个 Action 上面单独的配置路由模板.
    using System;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Routine.Api.Services;
    
    namespace Routine.Api.Controllers
    {
        [Route("api/Companies")]
        [ApiController]
        public class CompaniesController:ControllerBase
        {
            private readonly ICompanyRepository _companyRepository;
    
            public CompaniesController(ICompanyRepository companyRepository)
            {
                _companyRepository = companyRepository ?? throw new ArgumentNullException(nameof(companyRepository));
            }
    
    
            /// <summary>
            /// 获取所有公司信息
            /// </summary>
            [HttpGet]
            public async Task<IActionResult> GetCompanies()
            {
                var companies = await this._companyRepository.GetCompaniesAsync();
    
                if (companies == null)
                {
                    return NotFound();   
                }
    
                return Ok(companies);
            }
        }
    }
    

    代码编写好了,我们运行一下,发现报错了.

    修正代码:

                /*
                 * 端点中间件
                 */
                app.UseEndpoints(endpoints =>
                {
                    //endpoints.MapGet("/", async context =>
                    //{
                    //    await context.Response.WriteAsync("Hello World!");
                    //});
    
                    // 在使用了 [ApiController] 特性之后,我们就不需要再使用全局配置的路由表了,我们不应该再使用上述方法,
                    // 而是应该使用下列方法来描述端点 (MapControllers 表示统一的路由模板)
                    endpoints.MapControllers();
                });
  • 相关阅读:
    24点游戏算法
    汉诺塔算法
    台阶算法
    质因数分解算法
    全排列递归算法
    DFS 深度优先搜索例题
    容器
    数细胞
    C++栈和队列
    C++STL中vector容器 begin()与end()函数、front()与back()的用法
  • 原文地址:https://www.cnblogs.com/HelloZyjS/p/12577997.html
Copyright © 2011-2022 走看看