在 Web API 中传递枚举参数的最佳实践

Posted

技术标签:

【中文标题】在 Web API 中传递枚举参数的最佳实践【英文标题】:Best practice for passing enum params in Web API 【发布时间】:2017-02-08 22:21:20 【问题描述】:

我有一个 RESTful Web API 项目,我有 2 个不同的 Enum 场景,我不确定它们是否是最佳实践。

场景 1:简单的枚举参数

我的 API 方法需要一个名为 ruleType 的参数,有效值为 EmailAddressIPAddress。 我在 Web API 项目中的枚举如下所示:

public enum RuleType

    None = 0,
    EmailAddress = 1,
    IPAddress = 2

我对这种情况的问题是,我是否应该在对 API 的请求中使用 ?ruleType=EmailAddress(它会自动将该值绑定到 API 方法中的 RuleType 属性)?如果是这样,如何最好地验证发送的 RuleType 参数是有效的 RuleType Enum 值?

场景 2:单个参数的多个枚举值

我的 API 方法有一个可选的fields 参数,它允许您指定应返回的任何其他数据。例如。 &fields=ruleOwner,rule。这将在响应中返回这 2 位额外的数据。

我在 Web API 项目中有一个枚举,它与可能请求的每个可能的 field 相关,目前,我正在拆分逗号分隔的字段参数,然后循环遍历该枚举的每个字符串表示,解析它到等效的枚举,生成一个枚举值列表,然后我可以在我的 API 中使用这些值来检索相关数据。

这是枚举:

public enum OptionalField

    None = 0,
    RuleOwner = 1,
    Rule = 2,
    etc.

这里的最佳做法是什么?我正在研究按位枚举,因此在 API 请求中发送了一个值,这导致了 fields 的任意组合,但不知道这是否适用于 Web API,或者是否有更好的方法关于这个?

【问题讨论】:

【参考方案1】:

对于场景 2,C# 中内置了对使用 [Flags] 属性的枚举中的位掩码操作的支持

[Flags]
public enum OptionalField

    None = 0,
    RuleOwner = 1,
    Rule = 2,
    RuleAdministrator = 4,
    RuleEditor = 8,
    ...etc

这在this SO post中有描述

正如Christian 已经在他的回答中所述,在 REST API 中使用它可能不是一个好习惯,但它应该可以工作。

【讨论】:

[Flags] 属性与位掩码操作无关。这只是编译器将掩码值的名称解析为NameOne | NameTwo 的语法提示。不过,自然支持按位运算,因为您自己已经努力将枚举值设置为 2 的幂。【参考方案2】:

是否有多个值,如果您使用 Enum 作为字符串,则必须手动解析它。在 .NET 中,枚举是整数,因此如果您想将枚举发送到默认模型绑定器,您必须这样做:?ruleType=1

您可以编写自己的模型绑定器来接受字符串,但是您必须问自己为什么要这样做?如果您希望用户能够轻松识别 url,请使用字符串。如果不是,则没有理由不使用整数。如您所说,您可以使用 FlagsAttribute 组合多个值。

【讨论】:

使用字符串而不是数字是有充分理由的:数字是内部实现细节,而 API 是应用程序的公共前端。有正当理由要对enum 中的成员进行重新排序,但默认情况下这样做会更改数值——但不会更改名称。在代码内部,数值不应该有所不同,因为所有内容都引用相同的enum 定义。外部调用者没有获得这种好处,应该使用字符串形式来确保服务代码更新的一致性。 是的,但是如果您使用字符串,您将无法轻松发送复合值 ([Flags])。可以通过手动设置整数来解决排序问题。【参考方案3】:

最简单的答案是“没关系”。

如果你的控制器方法中的参数是枚举类型

public IHttpActionResult Foo(RuleType ruleType)

在 WebAPI 中,It Just Works - 无论客户端请求 URL 是否将参数值指定为 ?ruleType=1?ruleType=EmailAddress

如果客户端指定的值对枚举无效,则会引发异常(The parameters dictionary contains a null entry for parameter 'ruleType' of non-nullable type 'RuleType' for method 'Foo' ... 并且客户端会收到 400 Bad Request 响应。

【讨论】:

我喜欢那些与 ASP.NET Core 相关的 It Just Works 答案^_^ 如果 swagger 文档也将此查询参数的可能值描述为字符串,那就太好了;默认情况下,它似乎使用整数。这怎么能改变? @FrederikGheysels 这是一个 Swagger 配置选项。见***.com/questions/36452468/…【参考方案4】:

使 URI “人类可读”是最佳实践。所以我也可以理解你为什么使用 Enum 作为字符串。但正如 HristoKolev 所说,您必须编写一个自定义模型绑定器。

在我认为你不应该使用枚举组合的字段中。因为很难理解。也许您可以创建枚举的组合作为枚举条目

public enum OptionalField

    None = 0,
    RuleOwner = 1,
    Rule = 2,
    RuleAndRuleOwner = 3,
    etc.

【讨论】:

以上是关于在 Web API 中传递枚举参数的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

URI 和响应中参数的 API 最佳实践

在 Web API/OWIN 中使用大量声明的最佳实践

在 JSON 中传递美元金额的最佳实践是啥?

复制通过引用方法传递的参数的最佳实践,避免无意中修改参数

在另一个 Web API 中管理 Web API JWT 令牌的最佳实践

Web API 身份验证最佳实践