简体   繁体   中英

RESTful API URL design with authentication

My data model is like this:

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. The authentication is provided via OAuth 2 with a JWT token (that contains the logged user id).

First approach

Endpoints

The first idea for a URL structure is (the one I chose when there was still no authentication):

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

In this case a user with id 1 could use:

  • GET /users/1 to get their own information;
  • GET /users/1/items to get their own items (with rating);
  • GET /items to get all items that they could add to their collection.

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?).

Second approach

Endpoints

Given that you can extract the user id from the token, the structure could as well be more simple:

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

In this case a user with id 1 could use:

  • GET /users/me to get their own information;
  • GET /items?class=owned to get their own items (with rating);
  • GET /items?class=all to get all items that they could add to their collection.

Analysis

This solution is a bit messy but probably more elegant.

Good:

  • Shorter URLs;
  • Less redundancy ( GET /items to get your own 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);
  • Not straightforward to get other users' items (maybe something like 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?

You could look into a format like HAL. HAL gives you a way to describe specific resources (items) and allows you to create multiple collections that point to those resources.

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.

I put a lot of work into a hypermedia client: 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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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