WelcomeTo
WelcomeTo

Reputation: 20581

Transactions in REST API

I have some resource on which users must perform approve/reject workflow.

The problem I encountered is that I need in one transaction update current approval step and create new one. So I can do following:

Update current approval step (after user approves or rejects)

PUT myapi/approval_step/1 
{status: "approved"} // or status="rejected" 

And then create next approval step:

POST myapi/approval_step/
{...}

But I need both updating and creation in one transaction.

So how I can solve this problem and build elegant REST API for my case?

Most easy for me seems just to introduce reject and approve verbs, like:

POST myapi/approval_step/2/reject and POST myapi/approval_step/2/approve which will update existing approval step and create new one, but verbs should be avoided when designing REST API

Upvotes: 1

Views: 1430

Answers (2)

toniedzwiedz
toniedzwiedz

Reputation: 18553

It's not that using verbs is forbidden in URLs when you want to conform to the principles of REST. Using them is just a bad smell that could mean someone is trying to override protocol semantics.

For instance,

GET /myapi/createApproval

is terrible and wrong because the verb overrides the meaning of the HTTP verb GET and misuses it to implement a resource state transition, rendering the call unsafe.

HTTP is the underlying protocol of the web and conforming to its semantics has consequences that you need to foresee when designing an API. This has to do with idempotence and safety of methods. Conforming to these rules allows you to make sure that your API will be useful in terms of scalability, cacheability, conformance with proxies, etc.

In my opinion, it's fine to use verbs as long as you don't violate the rules defined by your underlying protocol. One could argue if a URL with verbs is a meaningful resource identifier. approve is less intuitive to think of as a resource than approval

You could go with

PUT    myapi/approval_step/2/approval

to mark the approval of a step and

DELETE myapi/approval_step/2/approval

to remove it.

Please note, however, that the format of the URL only seems relevant if you want actual developers to read some sort of documentation and write clients against it. This is more of a problem in terms of being RESTful than any verbs.

In a truly RESTful architecture, a human would never need to read or understand the URLs as the links could be obtained by the application client itself based on the hypermedia returned by a service. This requires using a well-defined format, though and is not an easy thing to do. Lots of supposedly RESTful APIs don't even bother to follow HATEOS.

For more information, see Roy Fielding's blog post, REST APIs must be hypertext-driven

HATEOAS, its pros and cons, as well as the design of hypermedia-driven APIs, concepts of resource state and application state are described in-depth in RESTful Web APIs by Leonard Richardson, Mike Amundsen and Sam Ruby. A really good read in my opinion. Not just to learn how to do REST but also to realize if you really want or need to do it.

Upvotes: 2

Pedro Werneck
Pedro Werneck

Reputation: 41898

First, you shouldn't make partial updates with PUT. PUT is a complete replacement of the target resource. So, for doing what you want, either PATCH or POST. Since you need updating and creating something new in the same operation, use POST. POST is the method to use for any operation that isn't standardized by the HTTP protocol, so you can do anything you want with it, as long as it's properly documented.

but verbs should be avoided when designing REST API

I really would love to know where the idea that verbs should be avoided when designing a REST API came from. It makes no sense, because the internal semantics of URIs are irrelevant in REST. An URI is an atomic identifier, and the meaning the text might have for an human is absolutely irrelevant for the application.

There's nothing wrong with doing:

POST myapi/approval_step/2/approve

What would be wrong is something like this:

POST myapi/approve

{"approval_step": 2}

I think someone read somewhere that this is wrong and for some reason concluded that it's because there's a verb in the URI, not because the resource is identified by the payload instead of the URI.

In case that's not clear, an even worse example would be doing something like this:

POST myapi

{"method": "approve"
 "args": {"approval_step": 2}}

This is clearly RPC, not REST, as all interaction with the API goes through a single endpoint, with the payload identifying everything you want to do. This is what you should avoid in REST, not the "verbs in URIs are wrong" nonsense.

Upvotes: 0

Related Questions