问题
I want to add actions to my REST API that would move 'resources' between different 'stores'.
For instance, suppose my resources are normally accessed by the following URL:
/resources
/resources/{resourceId}
Now suppose I want to 'deactivate' some resource, i.e. conceptually move it to another sub-folder. The most straightforward way to allow this would be as followed.
'Deactivate' the resource, i.e. cause it to be unavailable under /resources. Conceptually, it 'moves' the object to the '/resources/deactivated/' subfolder:
POST /resources/{resourceId}/deactivate
Or alternatively:
POST /resources/deactivated/{resourceId}
Get all the deactivated objects:
GET /resources/deactivated
Reverse the 'deactivate' action, i.e. conceptually move the object from the '/resources/deactivated/' subfolder back to the main one ('/resources').
Either
POST /resources/{resourceId}/reactivate
Or
POST /resources/deactivated/{resourceId}/restore
This API seems rather intuitive for me. But it seems to violate the 'prefer nouns' rules that I have seen in many best practices-articles on REST API: I use verbs and adjectives instead of nouns!
Note that I might have parameters for all the endpoints, e.g. GET /resources/deactivated?createdBefore=01022017
Are there any better alternatives for my REST API? I.e. more RESTful, but not less intuitive ones?
Good resources that I could find on the topic:
- Confusion Between Noun vs. Verb in Rest URLs
- GitHub's usage of verbs (POST /gists/:id/star, DELETE /gists/:id/star): https://stackoverflow.com/a/19648997/1847482
- Good point on needing to look for 'another object type': https://stackoverflow.com/a/2022938/1847482
回答1:
First of all, remember that REST stands for Representational State Transfer.
It is all about resources and their state. Operations such as activate, deactivate and move are all about replacing the current state of the resource with a new representation and you don't need verbs in the URL to express such operations.
For example, to replace a status of a resource, you can send a new representation of the resource in the payload of a PUT
request:
PUT /api/resources/[id]/status HTTP/1.1
Host: example.org
Content-Type: application/json
{ "status" : "active" }
It can be understood as replace the status of the resource identified by [id]
with the one sent in the request payload.
Then you could have the following to get the resources with a particular status:
GET /api/resources?status=active HTTP/1.1
Host: example.org
Accept: application/json
It can be understood as give me a representation of all resources with the status active
.
To move a resource to another folder, for example, you could have:
PUT /api/resources/[id]/folder HTTP/1.1
Host: example.org
Content-Type: application/json
{ "target" : "draft" }
It can be understood as replace the folder of the resource identified by [id]
with the one sent in the request payload.
回答2:
Is an active resource really that different than a deactivated resource? Consider just having a property that tracks active
ness. You can always filter them out, such as
GET /things?active=true
You can alter just that property with a microPUT
PUT /things/{id}/active
false
If a thing
and a deactivated-thing
are conceptually different, it's reasonable to have two separate endpoints. I would move between them using
POST `/deactivated-things`
{
"thing": "/things/12"
}
and
POST `/things`
{
"deactivated-thing": "/deactivated-things/12"
}
You should try to avoid a path having multiple meanings. For example, don't do this:
/resources/{id}
/resources/deactivated/{id}
Don't overload the meaning of the path segment after /resources
.
回答3:
Thanks Cassio for emphasizing the 'changing the object state' approach.
My own answer for completeness:
PATCH /resources/{resourceId} with body {"active":false} -- deactivate a resource
PATCH /resources/{resourceId} with body {"active":true} -- restore a resource
GET /resources -- return all 'normal' resources
GET /resources?includeInactive=true -- return all resources including the deactivated ones
GET /resources/{resourceId} -- return the resource
(The resources retrieved by 'GET' will contain the attribute 'active=true/false').
Seems like a classic case for PATCH: REST API PATCH or PUT
回答4:
One thing you never see mentioned with REST:
Don't confuse REST with web app or pretty urls.
eg. when a user logs in to edit their account, you would show
www.example.com/home
www.example.com/account
www.example.com/profile
and not
// www.example.com/users/{id} ...
www.example.com/users/433563444335634443356344
www.example.com/users/433563444335634443356344/edit
I think this is where many devs get confused. REST is great for APIs, but in terms of web apps, it should be used as the internal API for form action endpoints or ajax, for example, but not necessarily as the pretty url.
来源:https://stackoverflow.com/questions/43356344/alternatives-of-using-verbs-and-adjectives-in-restful-url