4

I have an RESTful api that allows my users to receive enquiries about their business e.g. 'I would like to book service x on date y. Is this available?'. The api saves this information as a resource to the following URI

users/{userId}/enquiries/{enquiryId}

The information shown when this resource is retrieved are the standard sort of things you'd expect from an enquiry - email, first_name, last_name, address, message

The api also allows customers to be created for a user. The customer has a login and password and also a profile. The following URIs expose these two resources

PUT users/{userId}/customers/{customerId}
PUT users/{userId}/customers/{customerId}/profile

The problem I am having is that I would like to have the ability to allow users to create a customer from an enquiry. For example, the user is able to offer their service on the date requested and will then want to setup a customer with login details etc to allow them to manage the rest of the process.

The obvious answer would be to use a URI like

 users/{userId}/enquiries/{enquiryId}/convert-to-client

The problem with this is is that it somewhat goes against a lot of what I've been reading about how to implement REST (specifically from the book Restful Web Services which suggests that URIs should point to resources not operations on resources).

The other option would be to get the client application (i.e. the code that calls the api) to handle some of this application logic. This doesn't quite feel right to me. I have implemented in my design that the client app is fairly dumb. It knows just enough to display the results from the API, and does not contain any application logic.

Would be great to hear what others views are on the best way of setting this up

Am I wrong to have no application logic in the client app? How would I perform this operation purely in the REST api?

1
  • what's wrong with having login on the client? convert-to-client then can be POST to users/{userId}/customers/ and DELETE to users/{userId}/enquiries/{enquiryId}
    – imel96
    Jul 1, 2013 at 22:47

3 Answers 3

5

I highly recommend reading RESTful Webservices, especially the chapters on the difference between RESTful and RPC style web programming; and the chapters on resource discovery and how to deal with the apparent need for "verbs" (they are usually a different resource in disguise).

Converting an enquiry to a customer does not need a "convert" verb. You wouldn't delete the enquiry just because you create a customer and thus you are simply creating a customer with the information from the enquiry as input.

POST /users/{userId}/customers?enquiry={EnguiryId}

or simply

POST /users/{userId}/customers

with the enquiry information in the request body.

By the way, I use POST on customers because that is the way to do it if the server application is in control of the identifier generation. Only use PUT to create resources if the caller is the one determining the identifiers.

On a side note: have you considered the security and privacy issues relating to including /users/{UserId} in your URI's? Anybody can now start trying different userid's to get at information of different users of your application. You really should consider leaving them off your URI's and having them determined by the authentication information that should be send with each request (and possibly refreshed with each response).

2
  • Great answer! I have read the book you mentioned. I'd actually totally forgotten about adding additional variables as a query. Will give it a go and re-read those sections.
    – GWed
    Jul 2, 2013 at 9:58
  • i would do it in the second way :) Mar 19, 2020 at 12:01
2

Taking into consideration the example you give I have a totally different look on it. The other answers are correct but I think this comes from a wrong starting point.

In fact an enquiry is a coming from a customer. A customer can maybe have multiple enquiries?

When you start to get the need of having a conversion step that means many times you have 2 resources which are about equal.

Why not have only the resource Customer at first. That resource contains all information about the client: email, first_name, last_name, address.

Status now: A Customer without enquiries. So that's a lead (you could add a boolean field for that status).

Then you could define 2 things: You could give the Customer a field with the message (first contact or something could that field be called).

Status now: You have a Customer with a message so you can filter them out and start answering them

Alternatively you create and enquiry for the Customer. So first create customer then enquiry. This could be done by the client, you make ClientId required to create an enquiry.

You could also make these 2 steps in one by allowing to create a new enquiry with optional fields (the customer address fields). That can take both steps at once. I don't particularly like it because it is less simple and in the end you get more complexity for almost no advantages.

Status now: You have a Customer with a related enquiry.

Now you have more Customers in your database then you might like. There you can filter them so you get the right list of clients. It's the same data so I believe it belongs in the same resource.

2
  • I like your approach and its nice to see you taking the time to approach the problem in a different way. For the application I am planning it is a requirement that a customer is created from an enquiry by an action performed by the user. But +1 for your answer
    – GWed
    Jul 2, 2013 at 8:37
  • Thanks for your reply. I understand your question and that is possible. Just add some boolean to your Customer in the back-end. It's different but it feels more logically structured. Jul 2, 2013 at 9:02
0

The problem with this is is that it somewhat goes against a lot of what I've been reading about how to implement REST (specifically from the book Restful Web Services which suggests that URIs should point to resources not operations on resources).

This is correct because the following operation that you suggested in your question would only be appropriate for a SOAP service. REST encourages that you not declare the service as an action of a resource in any way. The HTTP protocol defines the operation on the resource with GET, POST, PUT, DELETE, etc...

To be REST you perform an HTTP operation on a resource, and the result of this returns a Representation of said Resource (Get it? Representational State Transfer). If the client would like to GET an enquiry, they must change the representation of that resource and send that data back to the server. While you may be concerned about implementing this modification of data on the client, this is inherently not counter to any constraints defined by REST.

Source: Wikipedia: Representational State Transfer - Constraints

Code on demand (optional) Servers can temporarily extend or customize the functionality of a client by the transfer of executable code. Examples of this may include compiled components such as Java applets and client-side scripts such as JavaScript.

It is perfectly acceptable then to assume that a JSON object implemented in a proper Object-Oriented way will have defined script behavior about how to transform its data in a state that can be posted back to the server in order to convert it into a client. This functionality may not need to be complex, perhaps it is even just a property of the JSON object itself that when it POSTs back that the server understands it is to be converted.

The catch really is that the representation of this resource will change and this must be communicated or documented clearly to the clients of the service.

1
  • I don't fully understand your answer - its a little abstract. Could you maybe relate it more to the problem with some examples? Like how would you create the client from the enquiry?
    – GWed
    Jul 2, 2013 at 8:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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