Is using a verb in URL fundamentally incompatible with REST?
So let's say we have something that does not seem best represented as a resource (status of process that we want to pause, stateless calculation we want to perform on the server, etc).
If in API design we use either process/123/pause
or calculations/fibonacci
-- is that fundamentally incompatible with REST? So far from what I read it does not seem to, as long as these URLs are discoverable using HATEOAS and media types are standardized.
Or should I prefer to put action in the message as answered here?
Note 1:
I do understand that it is possible to rephrase some of my examples in terms of nouns. However I feel that for specific cases nouns do not work as well as verbs do. So I am trying to understand if having those verbs would be immediately unRESTful. And if it is, then why the recommendation is so strict and what benefits I may miss by not following it in those cases.
Note 2:
Answer "REST does not have any constraints on that" would be a valid answer (which would mean that this approach is RESTful). Answers "it depends on who you ask" or "it is a best practice" is not really answering the question. The question assumes concept of REST exist as a well-defined common term two people can use to refer to the same set of constraints. If the assumption itself is incorrect and formal discussion of REST is meaningless, please do say so.
It's not strictly about nouns vs. verbs; it's about whether you are:
What's a resource? Fielding defines it thusly:
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (eg "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (eg a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time."
Now, to your question. You can't just look at a URL and say, "Is such-and-such a URL fundamentally incompatible with REST?" because URLs in a REST system aren't really the important bit. It's more important that the URLs process/123/pause
and calculations/fibonacci
identify resources by the above definition. If they do, there isn't a REST constraint violation. If they don't, you're violating the uniform interface constraint of REST. Your example leads me to believe it does not fit the resource definition and therefore would violate this constraint.
To illustrate what a resource might be in this system, you could change the status of a process by POSTing it to the paused-processes
resource collection. Though that is perhaps an unusual way of working with processes, it's not fundamentally incompatible with the REST architecture style.
In the case of calculations, the calculations themselves might be the resource and that resource might look like this:
Request:
GET /calculations/5
Response:
{
fibonacci: 5,
prime-number: true,
square-root: 2.23607
}
Though again, that's a somewhat unusual concept of a resource. I suppose a slightly more typical use might look like this:
Request:
GET /stored-calculations/12381728 (note that URL is a random identifier)
Response:
{
number: 5,
fibonacci: 5,
prime-number: true,
square-root: 2.23607
}
though presumably you'd want to store additional information about that resource other than a sheer calculation that anyone can do with a calculator...
Response:
{
number: 5,
fibonacci: 5,
prime-number: true,
square-root: 2.23607,
last-accessed-date: 2013-10-28T00:00:00Z,
number-of-retrievals-of-this-resource: 183
}
This article has some nice tips: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
Quoting from the article:
What about actions that don't fit into the world of CRUD operations?
This is where things can get fuzzy. There are a number of approaches:
Restructure the action to appear like a field of a resource. This works if the action doesn't take parameters. For example an activate action could be mapped to a boolean activated field and updated via a PATCH to the resource.
Treat it like a sub-resource with RESTful principles. For example, GitHub's API lets you star a gist with PUT /gists/:id/star and unstar with DELETE /gists/:id/star.
Sometimes you really have no way to map the action to a sensible RESTful structure. For example, a multi-resource search doesn't really make sense to be applied to a specific resource's endpoint. In this case, /search would make the most sense even though it isn't a noun. This is OK - just do what's right from the perspective of the API consumer and make sure it's documented clearly to avoid confusion.
I personally like suggestion #2. If you need to pause something, what are you pausing? If it's a process with a name, then try this:
/process/{processName}/pause
It's considered bad practice to use verbs in your REST API.
There's some material on SO and elsewhere on why and how to avoid using verbs. That being said, there are plenty of "REST" APIs that use verbs.
For your process
API, I would make the resource Process have a state
field, which can be modified with a PUT
.
Suppose GET /process/$id
currently returns:
{
state: "PAUSED"
}
Then you PUT
this to /process/$id
:
{
state: "RUNNING"
}
which makes the process change state.
In the case of Fibonacci, just have a resource named fibonacci
, and use POST
with parameters (say n for the first n fibonacci numbers) in the body, or perhaps even GET
with a query in the URL.
上一篇: REST嵌套资源的最佳实践是什么?