6

We have a RESTful API that allows for creation of users by POSTing to a particular endpoint, api/v1/users

In the system, when a user is created, an email is sent to the user with content along the lines of "{Authenticated user} just added you to the super cool system and you can now do all sorts of things"

However, in some cases, when a user is created via the API, we don't WANT to send that email to them. Say it's some sort of import process or something - the developer has their data already, and does not want to send any such email.

The debate in our office is the following:

Viewpoint A: "This is an example of how RESTful web services fall down. Instead of POSTing to an endpoint for creating a thing, instead there should be command endpoints for each function that can be performed by the system, so each thing you can do is represented by a command, and if any metadata about that command is necessary, you can add it"

Viewpoint B: "The fact that you don't want thing x to happen when thing y is created means there are either two types of thing y, or thing y has a status which, if different, causes different things to happen when it is created. Therefore you can still adhere to strict RESTful principles"

Can this situation be reconciled with pure RESTful principles? Isn't the metadata a pollution of the "user" entity, and therefore an argument for there being commands for each thing you can do within the system? (Perhaps you can see which side of the argument I fall on...)

6

This isn't really related to the 'RESTfulness' of your api, you had certain business logic you wanted to apply when a user is created and that logic has now changed.

You could create a lower level of API with SaveUser and SendEmail and have your import script call SaveUser directly while the higher level api calls both.

Or you could add or amend you high level endpoint to accept a parameter indicating whether to send the email or not.

5

Q: In some cases, when a user is created via the API, we don't WANT to send that email to them. Say it's some sort of import process or something - the developer has their data already, and does not want to send any such email. Can this situation be reconciled with pure RESTful principles?

Yes, it can. Add a new endpoint and enforce the semantics of REST. The new endpoint executes a new service which performs the described functionality. From the business point of view, add user and import user are different use cases despite both might end up executing the same business rules and finish with the same results.

Q: Isn't the metadata a pollution of the "user" resource, and therefore an argument for there being commands for each thing you can do within the system?

Yes, it's. At least as Web REST services are usually conceived. But, who cares? If it's the best solution for the problem, then it's ok. But once at this point, consider making the second service RPC-like instead of reusing POST /API/v1/users.

For instance:1

POST /rpc/v1/resources

//Input data model.
{
    "method":"import"
    "params":{
          "resourceClass":"User",
          "resources":[
            {"name":"Jhon", "surname":"Conor"},
            {"name":"Sara", "surname":"Conor"}
          ],
          "notifications":false
     }
}

Why? Three reasons mainly

  1. The existing endpoint remains as it is and you don't introduce possible breaking changes or bugs. If the endpoint is already in production, backward compatibility is important.

  2. With a single RPC endpoint, you could implement several and different importers or execute commands on the server, leaving the navigability and discoverability to the API REST.

  3. Segregating read and write (CQRS) might help you to treat both as if they were different APIs and apply different rules, scale them up|out separately, etc. I dare to say that the final code source is going to be also easier to reason about.

Think that there's nothing wrong with enabling different endpoints (with different interfaces) to solve different problems. REST interfaces are not silver bullets. They solve specific concerns, while RPC interfaces solve others. Not everything can be affordable from REST. Even if you could do all of this with a pure RESTful interface maybe the benefits would not outweigh the costs.


1: I have used JSON-RPC like annotation but feel free to use any other.

3

Can this situation be reconciled with pure RESTful principles?

Absolutely.

Riddle: How would you do this with web browsers and applications and forms?

It would probably go something like this. The user would load a book mark (/web/A), which would have a bunch of links, and the user would read through the page to find a "create user" link. The user would follow that link to a form (/web/B) describing all the configuration options. The representation of that form would include a link to the form-submission-endpoint (/web/C), and when the user finally submitted the form, the server would go to work creating a new information resource from this request, and would eventually report that a new resource had been created at (/users/12345), or whatever. Meanwhile, one of the side effects would be that an email gets sent.

Now you introduce the requirement that we should be able to create a user without sending the email. So we prepare a new representation for (/web/A). The user loads the bookmark, reads through the page, sees "create user" -- that's not what I want -- keeps going, and eventually finds "create user no email". He follows that link to a form (/web/E)... the representation of /web/E probably looks a lot like the representation of /web/C, with the important difference that this form links to form-submission-endpoint (/web/F). The user submits the form, and the server -- observing which form was submitted to which endpoint, reports that a new resource is created at (/users/76890) but without send-the-email side effect.

What's the analog to this as a web API? The most common answer is to replace the media-type of the form submissions with application/json, and to skip the unnecessary bits - just document the schema of the message body and the existence of endpoints /json/C and /json/F that do the right thing.

What's the analog to this as a pure REST API? Just putting the links back into the representations of the process resources, so that the client discovers the endpoints by reading the representations, rather than reading out of band documents.

Whether you call that "different command endpoints", or "posting to command queues" or "content negotiation" or CQRS or whatever doesn't really matter. The main point of REST is making the endpoints discoverable, which gives you as the service providers the ability to move your endpoints around as you like.

Your team may want to discuss this image, taken from Ian S Robinsons talk: The Counterintuitive Web (2010)

enter image description here

The bottom approach is REST; the messages are constrained by the uniform interface. Specialization and innovation come about by expanding the resources to do what you need.

The top approach is RPC.

The middle approach is a disaster.

Howard Dierking (2016):

I believe that many API strategies, while well intentioned, end up being hamstrung by a faith-like allegiance to an incorrect understanding of REST.

2

The primary purpose of REST architectural style is to represent resources on the Internet, and to provide mechanisms for discovering them.

Is what you're doing trying to accomplish one of those two things? If it isn't, consider simply providing a sensible endpoint that accepts a POST and does what you want.

Alternatively, include a parameter in your RESTful URL that will steer the desired behavior.

1

Isn't the metadata a pollution of the "user" entity

Well HTTP is already a REST protocol, and the HTTP spec doesn't contain anything about not polluting your resource representation with meta-data.

When it comes to REST and you are in doubt about something just look how the web already works. Any time you download a PNG or JPEG file on a website over the web you are downloading a representation with tons of metadata. For example what camera took the photo, the software that edited it etc.

HTTP doesn't care about this, it just sends the current state of the resource in a representation format the server and client understand. The server or client might care about that metadata, and they are free to take any action they like based on that information, or simply ignore it.

This is specifically the advantage of REST, if HTTP did care about business domain stuff like that your communication protocol would break any time you changed your representation format. Instead I can use a web browser from 1996 to browser a website from 2016. The browser might not understand the representation format it receives (what is this HTML v5?) but I will get the resource.

If you define a representation of a User resource that has an defined value along the lines of expects_email=true there is no issue there with regards to it being some how unRestful.

The server is free to do something based on this or ignore it. You would then build your web server to have a side-effect that if it receives a new User resource in the state of expecting an email it actually sends the email.

The client isn't telling the server to send an email. It is telling the server 'Yo! I just created a new User and this user is in the state of expecting an email'. The client doesn't tell the server anything other than 'yo, here is a new resource' That is the limit to which REST cares. But you know that the server will send an email and you can define that in the representation spec so client developers will also know that happens when the server gets a User in that state.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.