【问题标题】:What is best practice for deleting multiple records by optional parameters in Core Web API?通过 Core Web API 中的可选参数删除多条记录的最佳做法是什么?
【发布时间】:2021-04-13 12:35:15
【问题描述】:

我正在为应用程序创建一个 Web API,并且我有一个针对资源的 DELETE 操作。资源为Names,都在一个SQLNames表中。每个名称都有一个Record 的外键(都在一个Records 表中),每个Record 都有一个FileNameIsValid 列。

这意味着我可以通过FileNameIsValid 或这些值的组合删除一堆Names。这正是使用 API 的应用程序所需要的。

但是,在我看到的所有 API DELETE 端点示例中,它们总是通过 id 删除一条记录,这让我怀疑我的方法是否被认为是最佳实践。

这也提出了一个问题,我什至要如何做我想做的事?目前,我的DELETE 端点Namesapi/Names/{fileName},我不确定如何将IsValid 也包含在其中。至少应该需要FileNameIsValid 值之一或两者。我不希望用户能够调用api/Names 并删除数据库中的每个名称。

在 NamesController 中删除操作:

[HttpDelete("{fileName}")]
public void DeleteBySourceFileName(string fileName)
{
    _repo.DeleteNamesByFileName(sourceFileName);
}

我曾考虑在操作中添加IsValid 作为查询参数,但这仍然需要fileName

最好的方法是什么?这样的端点是否适合 RESTful API?

【问题讨论】:

  • 我个人从不删除任何记录。您永远不知道将来是否需要它们。只需为“已删除”创建一个字段并将其设置为 0 或 1。(您可以使用布尔值,但我更喜欢 tinyints 而不是布尔值)所有其他逻辑都遵循是否设置了该值。除非您可以保证文件名是唯一的,否则您似乎也需要 UID。
  • 如果您要删除服务器上的文件,不妨考虑将文件移动到“已删除”文件夹中。使用 UID 和表名作为文件名的一部分。
  • @pcalkins 是否删除是另一个问题,但这里的主要问题是如何按照 restful 样式正确构建 URL。如果我们认为端点只是一个普通的 Web API 操作,这很简单,接受 POST 请求并获取删除操作所需的所有数据(文件名,...)。
  • 将您的操作标题更改为:[Route("~api/DeleteNames/{fileName})] [Route("~api/DeleteIsValid/{IsValid}")] [Route("~api /DeleteBoth/{fileName}/{IsValid}")] public void DeleteBySourceFileName(string fileName, bool?isValid) - 所有 3 条路由都应该在另一个下面
  • 我认为删除操作应该只接受一个 ID 并且应该要求确认。像这样按参数过滤确实看起来相当危险:D 我们会过滤,但通常结果会首先显示在 UI 上,以便用户清楚地看到应该删除的内容。当我们全部删除时有一个例外。

标签: c# rest asp.net-core asp.net-web-api .net-core


【解决方案1】:

我在邮递员中测试了这段代码。所有 3 个路由都正常工作。感谢@PavelAnikhouski 的 isValid:bool 想法。

        [Route("~/api/Delete/{fileName}")]
        [Route("~/api/Delete/{isValid:bool}")] 
        [Route("~/api/Delete/{fileName}/{isValid}")] 
        public  void Delete(string fileName, bool? isValid)
        {
            .....
        }

如果您愿意,您可以为每条路线使用不同的名称,而不是 Delete,例如“DeleteByFileName”或“DeleteIsValid”。它仍然可以正常工作。

【讨论】:

  • 确实有效!谢谢你。在我的代码中,我只是让端点说 Names 而不是 Delete,因为我们正在删除 Names 资源,并且在请求中的某处指定了对 Delete 的操作。
【解决方案2】:

如果您想遵循 RESTful 方法,我认为您可以遵循以下三种方法之一来一次删除多个项目:


  1. DELETE 带有查询字符串,如前所述:DELETE api/names?filenames={file name(s)}&isvalid={true|false}
    • 这很简单,但缺点是将过滤器声明为可选,您已经说过不是,因为您不允许删除所有名称。操作代码类似于:
[HttpDelete]
public Task Delete([FromQuery] string[] fileNames, [FromQuery] bool? isValid)
{
    // code to delete, but avoid delete with null/empty parameters (avoid delete all)
}

  1. POSTdeletions 资源,返回一个标识符,然后返回带有标识符的 DELETE,工作流程如下:

---> a) 发布请求,如:

POST api/names/deletions
{
   'filenames': [],
   'isValid': false
}

到一个编码如下的端点:

public class DeletionInput
{
    public string[] FileNames { get; set; }
    public bool? IsValid { get; set; }
}

[HttpPost("deletions")]
public Task<IActionResult> CreateDeletion([FromBody] DeletionInput input)
{
    // Based on the inputs, gather a list of Names to be deleted
    // and assign an ID to it. The ID is returned in the response
}

此端点的响应返回带有删除 ID 的位置(例如 api/names/deletions/3abf5784),以便客户端可以在之后下令有效删除。

---> b) 对创建的删除项的删除请求:DELETE api/names/deletions/3abf5784

  • 此请求删除与 ID 3abf5784 相关的名称列表。操作如下:
[HttpDelete("deletions/{id}")]
public Task<IActionResult> DeleteByDeletionId([FromRoute] string id)
{
    // the Names in the deletion list are effectively deleted only now
}

(有关此选项的更多信息here


  1. DELETE 与身体。 HTTP 删除请求可能有正文 (reference)。
  • 请求示例:
DELETE api/names
{
   'filenames': [],
   'isValid': false
}
  • 动作示例:
public class DeletionInput
{
    public string[] FileNames { get; set; }
    public bool? IsValid { get; set; }
}

[HttpDelete]
public Task<IActionResult> Delete([FromBody] DeletionInput input)
{
    // code to delete, but avoid delete with null/empty parameters (avoid delete all)
}
  • 这也是一个简单的选项。 ASP.NET 支持它,但可能有供应商不支持。但是,HTTP 规范允许这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-30
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多