简体   繁体   English

带有身份验证的 RESTful API URL 设计

[英]RESTful API URL design with authentication

My data model is like this:我的数据 model 是这样的:

User: id, email, hashed_password
Item: id, name, color
UserItem: user_id, item_id, rating

and I want to write a RESTful API to get these resources.我想写一个 RESTful API 来获取这些资源。 The authentication is provided via OAuth 2 with a JWT token (that contains the logged user id).身份验证通过 OAuth 2 提供,带有 JWT 令牌(包含记录的用户 ID)。

First approach第一种方法

Endpoints端点

The first idea for a URL structure is (the one I chose when there was still no authentication): URL 结构的第一个想法是(我在仍然没有身份验证时选择的那个):

/items/{item_id}
/users/{user_id}
/users/{user_id}/items/{item_id}

In this case a user with id 1 could use:在这种情况下,ID 为 1 的用户可以使用:

  • GET /users/1 to get their own information; GET /users/1获取自己的信息;
  • GET /users/1/items to get their own items (with rating); GET /users/1/items获取自己的物品(带有评分);
  • GET /items to get all items that they could add to their collection. GET /items以获取他们可以添加到他们的收藏中的所有项目。

Analysis分析

I think this solution is quite clear, but also unelegant.我认为这个解决方案很清楚,但也不优雅。

Good:好的:

  • You can easily get other users info (if they are available to them);您可以轻松获取其他用户信息(如果他们可用);
  • 1-to-1 relations between endpoints and data models.端点和数据模型之间的一对一关系。

Bad:坏的:

  • Longer URLs;较长的网址;
  • There is redundancy (why GET /users/1/items when in the token you already have the information about id 1?).存在冗余(为什么GET /users/1/items在令牌中您已经拥有有关 id 1 的信息?)。

Second approach第二种方法

Endpoints端点

Given that you can extract the user id from the token, the structure could as well be more simple:鉴于您可以从令牌中提取用户 ID,结构也可以更简单:

/items/{item_id}
/users/{user_id}

In this case a user with id 1 could use:在这种情况下,ID 为 1 的用户可以使用:

  • GET /users/me to get their own information; GET /users/me获取自己的信息;
  • GET /items?class=owned to get their own items (with rating); GET /items?class=owned获取自己的物品(带评级);
  • GET /items?class=all to get all items that they could add to their collection. GET /items?class=all以获取他们可以添加到他们的收藏中的所有项目。

Analysis分析

This solution is a bit messy but probably more elegant.这个解决方案有点混乱,但可能更优雅。

Good:好的:

  • Shorter URLs;较短的网址;
  • Less redundancy ( GET /items to get your own items).减少冗余( GET /items获取您自己的项目)。

Bad:坏的:

  • Only model UserItem is represented (even though in this case it is probably almost meaningless to get an Item without its rating, that could be set to null if the user has not yet added it);仅表示 model UserItem(即使在这种情况下,获得没有评级的项目可能几乎没有意义,如果用户尚未添加它,则可以将其设置为 null);
  • Not straightforward to get other users' items (maybe something like GET /items?user=3 ?).获取其他用户的项目并不简单(可能是GET /items?user=3之类的?)。

Conclusions结论

Honestly I don't know what is the best practice in this case.老实说,我不知道在这种情况下最好的做法是什么。 I feel like there is something off about both of these.我觉得这两个都有点不对劲。 Maybe there is an hybrid approach I'm not seeing?也许有一种我没有看到的混合方法?

How would you organize a model like this?您将如何组织这样的 model?

You could look into a format like HAL.您可以查看 HAL 之类的格式。 HAL gives you a way to describe specific resources (items) and allows you to create multiple collections that point to those resources. HAL 为您提供了一种描述特定资源(项目)的方法,并允许您创建指向这些资源的多个 collections。

This means that individual items could be hosted at /items/xyz , but items can be both part of the /user/a/items and /items collections.这意味着单个项目可以托管在/items/xyz ,但项目可以同时是/user/a/items/items collections 的一部分。

I put a lot of work into a hypermedia client: https://github.com/badgateway/ketting .我在一个超媒体客户端上做了很多工作: https://github.com/badgateway/ketting This is not just an ad though, there's alternatives but that approach of API design might we well-suited for you.这不仅仅是一个广告,还有其他选择,但 API 设计的方法可能我们非常适合您。

But regardless of the client you're using, systems like this can avoid the issue of retrieving the same item through multiple endpoints.但无论您使用哪种客户端,这样的系统都可以避免通过多个端点检索相同项目的问题。 A single item has a canonical url, and if the system is designed well you only have to retrieve an item once.单个项目具有规范的 url,如果系统设计良好,您只需检索一次项目。

A collection is just a list of links to the resources (items) that belong to that collection.集合只是指向属于该集合的资源(项目)的链接列表。 They point to the item, but don't 'contain it', just like a regular hyperlink.它们指向项目,但不“包含”,就像常规超链接一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM