Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Architectural REST: How do I design a REST API for request+approval, 2 resources or 1?

Tags:

rest

Let's say you are creating a REST API for a system that requires approval, e.g. a group membership system (closest analogy I can think of).

My resource for membership is /membership. I can see 3 possibilities:

A. Single resource.

So a new request is POST /api/membership which creates {group: 10, user:1, status:"pending"}. The org admin then approves by PATCH /api/membership/:membership {status: "member"}

Pro: single API. Con: Harder to easily differentiate between different member types; after all, a "pending" member isn't really a member. More importantly, a request to join isn't actually a membership.

B. Separate resources.

A new request is POST /api/join which creates a request to join {group: 10, user: 1, status:"pending"}. The org admin then approves by PATCH /api/join/:join {status: "approved"}. This then automatically (on the server) creates another resources at /api/membership/:membership.

Pro: Cleanly separates requests to join from actual memberships. Con: Seems redundant (the properties of a request and a membership are similar), and depends on automatically juggling one resource from another on the back-end.

C. Separate resources and requests.

Just like Option B, except that the org admin approves in 2 steps. First POST /api/membership {group:10, user:1} and then PATCH /api/join/:join {status:"approved"}.

Pro: Cleanly separates requests from actual memberships. Also does not rely on background processing of one resource to affect another. Con: Relying on the UI to do it is even messier!

Help?

like image 582
deitch Avatar asked Feb 14 '23 05:02

deitch


1 Answers

I would handle this as two separate resources. A membership request and a membership are two different things. In addition, they may happen to have very similar properties now, but if they diverge in the future you'll be stuck. I would do

POST /membership-requests
{
   "memberId": 7,
   "groupId": 15
}

to create the request. The admin could do

GET /membership-requests?groupId=15&status=pending

to get requests by group, and then

PUT /membership-requests/12345
{
    "status": "approved"
}

to approve the request. You could use server-side business logic to detect the status change and create the membership. That PUT could then return a link to the membership:

{
    "memberId": 7,
    "groupId": 15,
    "status": "approved",
    "membership": "/memberships/298"
}

If you do this, your business logic needs to make sure that only pending requests can have their status changed.

If you only use one resource, how will you handle rejected memberships? To me, it doesn't make sense to do a

GET /memberships?status=rejected

because if the request is rejected, that's not really a membership.

like image 188
Eric Stein Avatar answered May 12 '23 08:05

Eric Stein