理解RestfulApi

RestfulAPI简介

REST即Representational state transfer。

RestfulApi实际是一种创建api的风格,或者说是一种约定。它约定在创建api时:使用统一资源占位符表示资源,指定HttpMethod表示对应的操作(例如HttpGet表示获取,HttpPost表示创建,HttpDelete表示删除等),使用Http状态码表示请求结果状态。

关键词定义

  • 资源(Resources):是计算机(网络)中的数据,常见形式如图,文,声,像等,对于实际开发中它更多的是指业务数据(存在数据库中的数据)。
  • URI(Uniform Resource Identifier):统一资源定位符,我们通过URI即可访问对应的资源。
  • 表现层:数据的表现形式(格式)。
  • 状态转换:对数据进行操作(增删改查)。

Http常用请求方法

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

以上只列举常用的,当然还有不常用的Http请求方法,例如CONNECT,OPTIONS,HEAD等

Http状态码分类

  • 1**:信息,服务器收到请求,需要请求者继续执行操作
  • 2**:成功,操作被成功接收并处理
  • 3**:重定向,需要进一步的操作以完成请求
  • 4**:客户端错误,请求包含语法错误或无法完成请求
  • 5**:服务器错误,服务器在处理请求的过程中发生了错误

 

在NetCore中实现简单的RestfulApi

1.获取资源时一般使用HttpGet,但当参数较大时(一般使用对象承载)可以使用HttpPost

 1      /// <summary>
 2      /// get product by id
 3      /// </summary>
 4      /// <param name="id"></param>
 5      /// <returns></returns>
 6      [HttpGet("{id}")]
 7      [ProducesResponseType(StatusCodes.Status200OK)]
 8      [ProducesResponseType(StatusCodes.Status200OK)]
 9      public async Task<ActionResult<ApiResult<ProductModel>>> GetByIdAsync(Guid id)
10      { 
11          try
12          {
13              var productContract = await _productService.GetByIdAsync(id);
14              var productModel = _mapper.Map<ProductModel>(productContract);
15              return GetSuccessResult<ProductModel>(productModel);
16          } 
17          catch (Exception ex)
18          {
19              _logger.LogError(ex.ToString());
20              var internalErrorResult = GetInernalErrorResult();
21              return BadRequest(internalErrorResult);
22          } 
23      }

 

参数较大时(参数元素多,一般使用对象承载)使用HttpPost

 1      [HttpPost("Products")]
 2      public async Task<ActionResult<ApiResult<List<ProductModel>>>> MultiGetProductAsync([FromBody]ProductQueryModel model)
 3      {
 4          try
 5          {
 6              //TODO query product 
 7              return null;
 8          }
 9          catch (Exception ex)
10          {
11              _logger.LogError(ex.ToString());
12              var internalErrorResult = GetInernalErrorResult();
13              return BadRequest(internalErrorResult);
14          } 
15      }

 

2.创建对象使用HttpPost

 1      [HttpPost]
 2      [ProducesResponseType(StatusCodes.Status200OK)]
 3      [ProducesResponseType(StatusCodes.Status400BadRequest)]
 4      public async Task<ActionResult<ApiResult>> CreateProductAsync(ProductCreateModel model)
 5      {
 6          ApiResult result = null;
 7          if (model == null)
 8          {
 9              result = GetFailureResult(ApiResultCode.ParameterCannotBeNull, $"parameter can not be null");
10              return BadRequest(result);
11          }
12          try
13          {
14              var contract = _mapper.Map<ProductCreateContract>(model);
15              await _productService.CreateProductAsync(contract);
16              result = GetSuccessResult();
17              return result;
18          }
19          catch (PlatformException ex)
20          {
21              _logger.LogError(ex.ToString());
22              result = GetFailureResult(ex.ErrorCode);
23              return BadRequest(result);
24          }
25          catch (Exception ex)
26          {
27              _logger.LogError(ex.ToString());
28              var internalErrorResult = GetInernalErrorResult();
29              return BadRequest(internalErrorResult);
30          }
31      }

 

3.修改对象用HttpPut

 1      [HttpPut("{id}")]
 2      [ProducesResponseType(StatusCodes.Status200OK)]
 3      [ProducesResponseType(StatusCodes.Status400BadRequest)]
 4      public async Task<ActionResult<ApiResult>> UpdateProductAsync(Guid id, ProductEditModel model)
 5      {
 6          ApiResult result = null;
 7          try
 8          {
 9              var contract = _mapper.Map<ProductEditContract>(model);
10              await _productService.UpdateProductAsync(id, contract);
11              result = GetSuccessResult();
12              return result;
13          }
14          catch (PlatformException ex)
15          {
16              _logger.LogError(ex.ToString());
17              result = GetFailureResult(ex.ErrorCode);
18              return BadRequest(result);
19          }
20          catch (Exception ex)
21          {
22              _logger.LogError(ex.ToString());
23              var internalErrorResult = GetInernalErrorResult();
24              return BadRequest(internalErrorResult);
25          }
26      }

 

4.删除使用HttpDelete

 1      [HttpPut("{id}")]
 2      [ProducesResponseType(StatusCodes.Status200OK)]
 3      [ProducesResponseType(StatusCodes.Status400BadRequest)]
 4      public async Task<ActionResult<ApiResult>> UpdateProductAsync(Guid id, ProductEditModel model)
 5      {
 6          ApiResult result = null;
 7          try
 8          {
 9              var contract = _mapper.Map<ProductEditContract>(model);
10              await _productService.UpdateProductAsync(id, contract);
11              result = GetSuccessResult();
12              return result;
13          }
14          catch (PlatformException ex)
15          {
16              _logger.LogError(ex.ToString());
17              result = GetFailureResult(ex.ErrorCode);
18              return BadRequest(result);
19          }
20          catch (Exception ex)
21          {
22              _logger.LogError(ex.ToString());
23              var internalErrorResult = GetInernalErrorResult();
24              return BadRequest(internalErrorResult);
25          }
26      }

 

在NetCore中实现Restful风格的API

  1. 使用HttpGet、HttpPost、HttpPut、HttpDelete等指定请求方式(web api都应该遵循这个约定);
  2. 有时需要将指定参数限定到url中,用于明确资源。例如HttpGet("{id}");修改资源时HttpPut("{id}")
  3. 使用ProducesResponseType约定返回Http代码。(请求成功时是Http代码为200,请求失败时是400,也可以自行定义)。
  4. 使用ActionResult支持返回不同类型,例如BadRequest,Ok等。当直接返回实体结果及其就是默认为Ok。例如【return result;】和【return Ok(result)】是一样的
  5. 一般接口都是定义为Json格式的,也可以自定义对应的格式类型。

 

总结

Restful是一种api风格,它约定的URI的定义规范,资源状态转换(增删改查)时应使用对应的HttpMethod进行操作。这样在开发中就可以很明了的知道api的功能,而不会造成不必要的误解。

但是在实际的开发中,其实也可以多对应的扩展,不必太拘泥于这样的规范。不要为了想一个很贴切的URI而耗时半天,也不用因为当查询条件很多时,还一定要使用HttpGet(Url是限定长度的)。

posted on 2022-03-07 22:50  john_yong  阅读(107)  评论(0编辑  收藏  举报

导航