Buğra Ekuklu
Buğra Ekuklu

Reputation: 3278

Updating many-to-many association with REST

I have three different models as User, PermissionSet and Permission. These models represent their SQL tables respectively.

User has a many-to-one association PermissionSet, a user may have one PermissionSet or none. PermissionSets would be owned by none or many Users.

PermissionSet has many-to-many association with Permissions. A Permission could be owned by multiple PermissionSets or none, where PermissionSets may own multiple Permissions or none at all.

So I created four tables: users, permission_sets, permissions and a junction table, permission_sets_permissions.

I need to persist the changes made in a User's PermissionSet. This is handled by a model called PermissionSetGrant, which has its own table, permission_set_grants.

What is the best way to alter the Permissions of a PermissionSet with a RESTful API, based on HTTP and JSON?

For example, is it a good way to modify a PermissionSet with such request:

PUT /api/v1/permission_sets/7

//  Payload
{
    "permission_set": {
        //  Assume these properties of the entity aren't changed
        "name": "default",
        "description": "Default permission set.",

        //  Here we're changing the permissions
        "permission_ids": [
            24,
            27,
            35
        ]
    }
}

-> 200 OK

or add permissions with an extra REST path instead?

POST /api/v1/permission_sets/7/permissions

//  Payload
{
    "permission": 24
}

-> 201 CREATED

and when we need to delete that permission

DELETE /api/v1/permission_sets/7/permissions/24

-> 203 ACCEPTED

I would also add that the request is idempotent and deterministic from the client's aspect. The number of permissions is 100, at least. Hence, batch operations will be performed in second approach.

Upvotes: 3

Views: 728

Answers (2)

inf3rno
inf3rno

Reputation: 26129

Your current solution is okay I think. If all you want to connect permissions with permissions sets, then you can use multiple ids to describe collections instead of using the payload for the same, e.g.

PUT /api/v1/permission_sets/1+2+3/permissions/4+5+6/
DELETE /api/v1/permission_sets/1+2+3/permissions/4+5+6/

If I were you I would not stuck by hierarchical URI design, it is inconvenient by most of the time.

PUT /api/v1/permissions/4+5+6/into/permission/sets/1+2+3/
DELETE /api/v1/permissions/4+5+6/from/permission/sets/1+2+3/

Be aware that there are not REST constraints about URI design, since REST operates with hyperlinks and machine clients. So from a client perspective it does not matter what structure the URI has as long as it can be described with an URI template. The only thing you have to keep in mind, that there is n:1 relation between URIs and resources, so multiple URIs can identify the same resource, but a single URI cannot identify multiple resources.

Upvotes: 1

Alex Marculescu
Alex Marculescu

Reputation: 5770

If you're going to allow the update of such a large number of permissions at once, then PATCH might be your friend:

Looking at the RFC 6902 (which defines the Patch standard), from the client's perspective the API could be called like

PATCH /api/v1/permission_sets/7
[
    { "op": "add", "path": "/permission_ids", "value": [ "24", "27", "35" ]}
]

However, PATCH is not an idempotent method unfortunately (and neither is POST, for pretty much the same obvious reason), so by exclusion you're left with the PUT, which is fine, just a bit more verbose than the PATCH (the client has to PUT the whole object, including the whole collection of permission_ids).

Upvotes: 0

Related Questions