architectural design for REST API with views acros

2019-07-28 16:48发布

问题:

Looking for some input on a REST API architectural design. I often find that the desired data is the combination of a view across multiple resources. Would you expect the client to combine them, or provide an API that does the combination for the client?

For example, let's say we are writing a REST API for people to become notified about events. Someone will indicate interest in an event in one of 2 ways:

  • Join an organization that regularly puts on events that the person has interest in
  • Search for and then mark a particular event run by an organization I wouldn't normally subscribe to

I can retrieve all of the events for user 100 by doing the following long steps:

  1. GET /user/100/organizations returns 123
  2. GET /organizations/123/events returns [15,16,20]
  3. GET /user/100/savedevents returns [35,36]
  4. GET /events/15,16,20,35,36 returns all of the events

But that seems rather heavy for a client. I almost want a client to be able to say, "give me all of the interesting events for this user":

GET /user/100/events

...and then require the server to understand that it has to go through all of steps 1-4 and return them, or, at the very least, return [15,16,20,35,36] so it becomes 2 steps: get event IDs; get event details.

Does this even make sense, to make a view that cuts across multiple resources that way?

EDIT: To explain further. My hesitation is because I can see how /organizations/123/events is a clean resource; if is identical to saying /events?organizations=123, i.e. "give me resource events where organizations=123". Same for /user/100/organizations.

But /user/100/events is not "give me resource events where organizations=123". It is "give me organizations registrations where user=100, retrieve those organization ids, then give me the events where the organization=123, then give me savedevents where user=100."

Each of the three steps itself is a clean resource mapping. Putting them together seems messy. But so does asking a client (especially a Web client), to figure out all that logic!

回答1:

There may be several ways to solve this... however, I think that most of the times (if the service is managed by the same provider) it is better to have the logic on the server-side and make REST calls as independent as possible of each other (i.e., the server performing the multiple operations required - normally read data from DBs that are store the data handled in the API resources).

In the example you talk about this would mean your REST API would expose a "user" resource and a sub-resource "events" (which you call "savedevents") he is interested in. With this in mind you would have something like this:

  • POST /user/{username}/events stores a new event (or multiple events) the user is interested in
  • GET /user/{username}/events returns all the events the user is interested in
  • GET /user/{username}/events/{eventid} returns details of a specific event

To "filter" user events per organization (and other filtering operations) you can use "query parameters":

  • GET /user/{username}/events?organization=123

So, the server (or API call) would perform the operations you describe from step 1 to step 4 in the GET /user/{username}/events. You can still make the other resources ("organizations" and "events") in your API, however they would be used in other contexts (like store new events or organizations, etc.).

HTH



回答2:

I was a bit confused by your question, so I'll try to be as comprehensive as possible and hopefully I'll have hit on an answer you need =P.

I often find that the desired data is the combination of a view across multiple resources. Would you expect the client to combine them, or provide an API that does the combination for the client?

In a true RESTful environment all cross-sectional views of data would be done by the server, not by the client.

The primary reason for a RESTful design is allow access to the CRUD model (create, read, update, delete) by way of using standard HTTP verbs (e.g. GET, POST, PUT, DELETE). Storing the returns of these methods in some sort of session or cookie or otherwise external method (e.g. "give me data for bob", "give me data on businesses", "give me data from my first two queries") goes above and beyond the REST methodology.

The way you'll want to leverage RESTful development is to find ways of combining resources in meaningful ways so as to provide a RESTful environment where the method calls are consistent; GET reads data, POST creates data, PUT updates data, DELETE deletes data).

So if you wanted to do something like Steps 1 through 4 I'd recommend something like:

GET /user/{userID}/organizations --> {return all affiliated organizations}
GET /user/{userID}/events --> {return all events associated with userID}
GET /organizations/{organization}/events --> {returns all eventID's assoc. with organization}
GET /user/{userID}/savedevents -->  {return all eventID's userID saved to their profile}
GET /events/?eventID=(15,16,20,35,36) --> {return all of the events details for those eventID's}
GET /events/{eventID}--> {return events details for {eventID}}

Whereas you might also have:

GET /events/  --> {return a complete listing of all event ID's}
GET /events/{userID}  -->  {return all events userID is associated with}
POST /event/  --> {create a new event - ID is assigned by the server}
POST /user/   --> {create a new user - ID is assigned by the server}
PUT /user/{userID}  --> {update/modify user information}

Then if you want cross-sectional slices of information, you would have a named resource for the cross section (else pass it as arguments). Be explicit with your resources (Random FYI, name your resources as nouns only - not verbs).

You also asked:

To explain further. My hesitation is because I can see how /organizations/123/events is a clean resource; if is identical to saying /events?organizations=123, i.e. "give me resource events where organizations=123". Same for /user/100/organizations.

Essentially both the named resourced and the resource + argument method can provide the same information. Typically I have seen RESTful design API call for arguments only when an important delineation is required (range requests, date requests, some REALLY small unit of data, etc.). If you have some higher-order grouping of data that CAN BE parsed/introspected further then it's a named resource. In your example, I'd have it both API calls, as the RESTful spec calls for providing data via multiple paths and by way of using the established HTTP methods. However, I'd also expand a bit...

/events?organizations=123 -->  {return the eventID's associated with org=123}
/organizations/123/events  -->  {return event DETAILS for events associated with org=123}

Have a read/go at this, by Apigee



标签: rest