【问题标题】:A restful service API designing issue一个restful服务API设计问题
【发布时间】:2013-08-06 05:55:52
【问题描述】:

关于restful服务API设计的一个问题。我不确定如何以正确的方式做到这一点。请给我一些建议。

我的场景是这样的。我有一个用户资源和权限资源。

http://www.sample.com/rest/users
http://www.sample.com/rest/permissions

用户可以拥有多个权限;一个权限可用于多个用户;这是多对多的关系。

通常,我们可以说权限属于用户,所以我们有一个 API,例如:

http://www.sample.com/rest/users/{userId}/permissions

当我们想在权限和用户之间建立关系时,这里有两个选项。

  1. 我们可以先使用POST:http://www.sample.com/rest/permissions 使用权限主体,然后 POST: http://www.sample.com/rest/users/{userId}/permissions有一套 权限 ID。我不确定是否还有其他的 REST API 像这样设计。

  2. 我们只能使用一种 API,例如: http://www.sample.com/rest/users/{userId}/permissions 与 权限对象内容。在这个方法中,我们做两件事 选项 1 中的描述。缺点是我们不能永远重用 已创建权限,看起来一个用户可以拥有多个 权限,但一项权限仅由一位用户使用,服从 我们的第一个设计。但是对用户来说真的很简单。

如果您对此主题有任何经验,欢迎提出任何建议。

【问题讨论】:

    标签: rest wcf-rest restful-architecture


    【解决方案1】:

    如果权限对象复杂到看起来像一个单独的实体(或者如果您需要在用户之间共享权限对象),我将使用单独的权限 URL。如果权限“对象”只是一个rwx 字符串或类似的东西,那么不值得引入一个独立的实体。另一方面,如果权限对象更复杂(例如与文件夹列表关联的权限列表),则将其存储为单独的实体并为此使用单独的 URL 可能是有意义的。

    【讨论】:

    • 我认为拥有权限实体的主要论据是它可以很容易地更新共享该实体的所有用户的权限。如果每个用户都有自己的rwx 设置,正如您所建议的那样,但您想始终如一地更改其中的大量用户,那么这是一项非常重要的操作。但是,如果您只想更新一个“permisionX”,那么一次更改,成千上万的用户都在不断更改。
    【解决方案2】:

    另一种方法是将用户和权限视为分离的“空间”或资源。您应该能够使用 CRUD 单独管理它们。

    创建用户

    • POST:/users/
    • 返回:{userid}

    创建权限

    • POST:/permissions/
    • 返回:{permid}

    然后来映射,你应该改用PUT,因为它不是创建新资源而是映射两个资源

    将用户添加到权限空间

    • PUT:/permissions/users/{userId}/

    或将用户添加到权限空间

    • PUT:/permissions/users/
    • 正文:{[userid1, userid2, ...]}

    为用户空间添加权限

    • PUT:/users/permissions/{permId}/

    或者给用户空间添加权限

    • PUT:/用户/权限
    • 主体:{[permid1, permid2, ... ]}

    【讨论】:

    • 我认为还应该将 api 版本保留在 url 中,因此如果将来需要大幅更改 API,应该能够在不触及旧 api 的情况下这样做。所以像这样的网址sample.com/rest/1.0/users
    • 我认为你关于“应该使用 PUT”的说法是完全错误的。 /user/{id}/permissions/ 是一个集合,显示此用户 拥有的权限资源(不是整个系统),它应该是该用户拥有的权限的URI 列表(即/permissions/3 \n /permissions/666 \n /permissions/7)。如果您要使用GET 其中之一,例如GET /permissions/3,它将返回该一个权限资源,例如name=admin,它还应该具有指向/permissions/3/users的链接,即一个集合资源,列出拥有此权限的用户。
    【解决方案3】:

    资源

    首先让我们来谈谈您将拥有哪些“资源”和“收藏”。

    • /users/permissions 是一个不错的简单开始,它们分别是所有用户和所有权限的集合。
    • /users/{id}/permissions/{id},它们分别是用户或权限的单个资源。
      • 用户可能拥有“姓名”、“注册日期”、“身份证”等字段。
      • 权限可能包含“名称”、“创建日期”、“ID”等字段。

    到目前为止很好很简单。不管你从这里走到哪里,这两种类型的资源仍然作为独立的实体存在,一个用户可以没有权限,一个权限可以没有用户。但是现在我们需要将这些链接在一起吗?首先,让我们展示一个看似简单却让大多数人大吃一惊的概念......

    /users/{id}/name 可用于仅返回基于 ID 的用户名。你没有支持这种行为,如果你这样做了,那么你不应该直接将名称作为“用户”资源的一部分返回(你应该链接到这个特定的名称资源)。

    这个概念也可以应用于权限。因此,我们还添加了/users/{id}/permissions,既可以作为可以调用GET 的资源,也可以作为通过/users/{id} 调用GET 的资源中的“链接”(因此hyper 开始使用 html 的一部分)。那么这会返回什么呢?可能是这样的:

    /permission/3
    /permission/666
    /permission/7
    

    这些资源是否“在”用户之下,不。他们需要吗,不。那么如果你GET 这些权限资源之一呢?

    name=admin
    id=666
    created-date=12/3/45
    users=/permission/666/users
    

    最后一行,就像一个用户拥有一组权限一样,一个权限拥有一组拥有它的用户。 (我想你可以弄清楚那会是什么样子)

    创建资源

    在第一部分中,我介绍了这两种类型的资源如何相互关联。但是,您的问题更多是关于如何创建这些资源。显然,您可以允许操作员(我会说操作员以避免与“用户”资源混淆)创建用户,同时定义他们应该拥有的权限:

    { "name" : "Frank",
      "permissions" : [
        ...
      ]
    }
    

    服务器会为您生成“id”和“sign-up-date”。权限列表可以允许使用“id”或“名称”,后者将要求服务器确保它们是唯一的并且还让服务器进行查找。此时唯一的问题是,如果“权限”是一个新名称……服务器会做什么?它可以很容易地创建它,但如果它是一个错字,或者只是一个大小写问题怎么办?

    确实,它应该是 ID,并且这些应该在创建用户之前就已经存在。 GUI 可以帮助操作员找出这些 ID 是什么(提供“角色”名称列表,但知道如何发送带有 ID 的 POST 请求)。

    作为旁注,请注意没有什么可以阻止创建没有权限的用户,并且可以在以后根据需要修改用户拥有的权限集合。

    回答实际问题

    它归结为两个简单的事情。首先,您可以有多个 URI 引用同一个资源; /permissions/666 可能是规范的 URI,但如果用户拥有该权限,您也可以通过 /user/{userID}/permissions/666 找到它,这两个 URI 可以引用服务器上的相同资源。

    要考虑的第二件事,这确实使答案看起来很明显(尤其是在这个用例中)。您多久创建一次权限?您可能会制作 10 个,但随后将其中一些分配给数千名用户。因此,试图弄清楚如何在一个请求中处理创建权限和用户资源似乎是可耻的愚蠢。正如我认为我已经表明的那样,重复使用它不是问题。

    TL;DR

    您提出的第一个解决方案是可行的方法。


    一个更具挑战性的话题是如何删除权限。来自单个用户或完全删除它。但是我已经讲了足够长的时间,所以也许另一个答案可以专门关注那个细节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 2012-02-03
      • 1970-01-01
      • 2011-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多