【问题标题】:REST API POST/PUT with different set of requests具有不同请求集的 REST API POST/PUT
【发布时间】:2018-12-13 21:32:42
【问题描述】:

创建/修改资源的 post 或 put 方法能否接受不同的请求对象集?

例如:我有一个名为'server' 的资源。它可以通过它的操作系统来区分。例如,我可以有两个资源实例 - windows serverlinux server。 我在这里的基本决定是将它们视为相同类型的资源,即server

现在,创建 Windows 服务器可能会发生,我的 POST API 接受的请求对象与相同 API 用于 linux 服务器的请求对象不同。

为了创建 Windows 服务器,我有 -

POST : /v1/server
accepts 
{
    name : win-server-1
    os : 'windows'
    ms-office: 'Office2009'
}

为了创建 linux 服务器,我使用相同的 api 但使用不同的请求对象 -

POST : /v1/server
accepts
{
   name : linux-server-1,
   os : 'linux'
   kernel-version : '3.10.0' 
}

如您所见,相同 POST API 接受的请求对于 windows 和 linux 服务器是不同的。我的业务逻辑将根据'os' 属性处理这些请求。所以从技术上讲,它会起作用(使用丑陋的开关盒)。 但这真的很平静吗?或者我应该有不同的 API,例如 /v1/windows-server/v1/linux-server,并为每个 API 定义唯一的请求定义?

【问题讨论】:

    标签: rest api-design


    【解决方案1】:

    从客户的 POV 来看,最好有一个端点。请注意,拥有单独的资源会将“丑陋的切换”的必要性转移到客户端。

    我会采用您当前的解决方案。客户的便利性和 API 的清晰性/简单性比开发人员的更重要。 API 比实现更重要。恕我直言,您当前的解决方案在这方面更好:

    • 创建:POST /v1/servers
    • fetch:GET /v1/servers/{server_id}POST /v1/servers/{server_name}(给定名称是唯一的)返回单个资源
    • 查询:GET /v1/servers/?{filter_expression}(例如GET /v1/servers/?os=linux)返回(过滤的)资源的集合(最好带有分页)

    我要更改的一件事是将特定于操作系统的内容提取到嵌套资源中。这将使实现更简单,API 更清晰:

    {
        name : win-server-1,
        os : 'windows',
        config: {
            ms-office: 'Office2009'
        }
    }
    
    {
        name : linux-server-1,
        os : 'linux',
        config: {
            kernel-version : '3.10.0' 
        }
    }
    

    【讨论】:

    • 感谢您的回复! IMO 开关盒将仍然存在。客户端必须根据服务器操作系统类型切换“配置”对象的创建。我们没有为那里的客户保存任何东西。此外,很难记录(使用像 swagger 这样的工具)相同 API 的不同配置定义。您的建议确实很公平,但想知道将它们记录为两个不同的 API 会更清晰,还是一个具有所有不同配置设置的 API。
    • 关于文档 - 我在这里没有看到问题,但无论如何我不会让文档强制 API 决策。
    • 想象一下 UI:可能是一个用于选择操作系统类型的组合框。只要我们有一个端点,这里就没有开关。
    • 请注意,客户端必须将操作系统类型放在某处。您在此处做出的选择是它是放在 URL 中还是放在请求正文中。
    【解决方案2】:

    但它真的很安静吗?

    测试该问题的一个好方法是询问您尝试做的事情与网络的匹配程度。

    在这种情况下,类比将有两个不同的表单,它们向表单操作属性描述的相同目标 URI 提交请求。

    windows: <form action="/v1/server" method="post">
        <!-- ... -->
        Office: <input type="text" name="config.office"><br>
        <input type="submit" value="Submit">
    </form> 
    
    linux: <form action="/v1/server" method="post">
        <!-- ... -->
        Kernel-version: <input type="text" name="config.kernel-version"><br>
        <input type="submit" value="Submit">
    </form>
    

    任何符合标准的网络客户端都可以很好地处理这个问题。 text/html 媒体类型的处理规则告诉客户端如何从这些表单中构造一个请求。

    请注意,由于浏览器只是在处理 form.action,因此您可以轻松更改资源标识符。所以如果你后来决定 windows 和 linux 请求应该使用不同的请求,你可以很容易地做到这一点:

    windows: <form action="/v1/windows-server" method="post">
        <!-- ... -->
        Office: <input type="text" name="config.office"><br>
        <input type="submit" value="Submit">
    </form> 
    
    linux: <form action="/v1/linux-server" method="post">
        <!-- ... -->
        Kernel-version: <input type="text" name="config.kernel-version"><br>
        <input type="submit" value="Submit">
    </form>
    

    但它真的很安静吗?

    “真正安静”与服务器如何处理请求的关系相对较小——更重要的是了解服务器如何描述对客户端的请求(又名hypermedia)。

    【讨论】:

      【解决方案3】:

      我会选择/v1/server/linux/v1/server/windows。这将允许您保留 /v1/server,例如用于 GET。

      POST : /v1/server - 正如你所说,这将需要更多代码和一些“丑陋的开关案例”。当有人要求您添加新类型的服务器时,这种方法也将更难维护和开发。

      /v1/linux-serverand/v1/windows-server - 我认为这也是一个好方法。只有 2 种类型,拥有单独的端点并不是什么大问题。使用较大的数字,/v1/server/{os_type} 在文档中看起来更好,并且比 X 个单独的端点列表更具可读性。

      【讨论】:

      • 感谢您的回复!但是如果我不想在 url 中引入层次结构怎么办。这是一个非常不必要的问题吗?因此,我可能拥有 /v1/linux-servers 和 /v1/windows-server,而不是使用显示 /v1/server/linux 的 API。仍然为 GET 保留 /v1/servers。
      • 通常/v1/server/{here}这部分是为资源标识符保留的。我不会把过滤表达式放在那里。
      猜你喜欢
      • 2022-06-19
      • 1970-01-01
      • 2013-06-22
      • 2018-07-14
      • 2018-08-04
      • 2019-09-15
      • 1970-01-01
      • 2018-08-23
      • 1970-01-01
      相关资源
      最近更新 更多