How to obtain the id of a record resulting from a HTTP POST? - iphone

I've implemented an iPhone App that uses a RESTful HTTP POST to register itself with a web server via Rails.
Some time later, the App needs to update its own record on the server, and so needs to know the id of its own record for the RESTful HTTP PUT path.
However, the App was never told the id of its own record on the web server resulting from the POST. So, it then needs to search for it on the server using the device's UDID (stored in the record), return the corresponding id, and then construct a RESTful URL based on that... this all seems rather cumbersome.
Is there a more elegant design-pattern for this? (it would be convenient if the original POST returned some data that allowed me to obtain the record id, but it doesn't seem to).
Thanks.

To close this question off, the answer, which was supplied by Oscar Del Ben above, is that it is indeed necessary to find the record using some other unique key e.g. UDID, and update that record with a POST once retrieved.
(of course, the POST also returns the created record, with id, so it could be saved that way, if the design allows)

Related

REST endpoint for complex actions

I have a REST API which serves data from the database to the frontend React app and to Android app.
The API have multiple common endpoints for each model:
- GET /model/<id> to retrieve a single object
- POST /model to create
- PATCH /model/<id> to update a single model
- GET /model to list objects
- DELETE /model/<id> to delete an object
Currently I'm developing an Android app and I find such scheme to make me do many extra requests to the API. For example, each Order object has a user_creator entry. So, if I want to delete all the orders created by specified user I need to
1) List all users GET /user
2) Select the one I need
3) List all orders he created GET /order?user=user_id
4) Select the order I want to delete
5) Delete the order DELETE /order/<id>
I'm wondering whether this will be okay to add several endpoints like GET /order/delete?user=user_id. By doing this I can get rid of action 4 and 5. And all the filtering will be done at the backend. However it seems to me as a bad architecture solution because all the APIs I've used before don't have such methods and all the filtering, sorting and other "beautifying" stuff is usually at the API user side, not the backend.
In your answer please offer a solution that is the best in your opinion for this problem and explain your point of view at least in brief, so I can learn from it
Taking your problem is in isolation:
You have an Order collection and a User collection
User 1..* Orders
You want to delete all orders for a given user ID
I would use the following URI:
// delete all orders for a given user
POST /users/:id/orders/delete
Naturally, this shows the relationship between Users & Orders and is self-explanatory that you are only dealing with orders associated with a particular user. Also, given the operation will result in side-effects on the server then you should POST rather than GET (reading a resource should never change the server). The same logic could be used to create an endpoint for pulling only user orders e.g.
// get all orders for a given user
GET /users/:id/orders
The application domain of HTTP is the transfer of documents over a network. Your "REST API" is a facade that acts like a document store, and performs useful work as a side effect of transferring documents. See Jim Webber (2011).
So the basic idioms are that we post a document, or we send a bunch of edits to an existing document, and the server interprets those changes and does something useful.
So a simple protocol, based on the existing remote authoring semantics, might look like
GET /orders?user=user_id
Make local edits to the representation of that list provided by the server
PUT /orders?user=user_id
The semantics of how to do that are something that needs to be understood by both ends of the exchange. Maybe you remove unwanted items from the list? Maybe there is a status entry for each record in the list, and you change the status from active to expired.
On the web, instead of remote authoring semantics we tend to instead use form submissions. You get a blank form from somewhere, you fill it out yourself, you post it to the indicated inbox, and the person responsible for processing that inbox does the work.
So we load a blank form into our browser, and we make our changes to it, and then we post it to the resource listed in the form.
GET /the-blank-form?user=user_id
Make changes in the form...
POST ????
What should the target-uri be? The web browser doesn't care; it is just going to submit the form to whatever target is specified by the representation it received. One answer might be to send it right back where we got it:
POST /the-blank-form?user=user_id
And that works fine (as long as you manage the metadata correctly). Another possibility is to instead send the changes to the resource you expect to reflect those changes:
POST /orders?user=user_id
and it turns out that works fine too. HTTP has interesting cache invalidation semantics built into the specification, so we can make sure the client's stale copy or the orders collection resource is invalidated by using that same resource as the target of the POST call.
Currently my API satisfies the table from the bottom of the REST, so, any extra endpoint will break it. Will it be fatal or not, that's the question.
No, it will be fine -- just add/extend a POST handler on the appropriate resource to handle the new semantics.
Longer answer: the table in wikipedia is a good representation of common practices; but common practices aren't quite on the mark. Part of the problem is that REST includes a uniform interface. Among other things, that means that all resources understand the same message semantics. The notion of "collection resources" vs "member resources" doesn't exist in REST -- the semantics are the same for both.
Another way of saying this is that a general-purpose component never knows if the resource it is talking to is a collection or a member. All unsafe methods (POST/PUT/PATCH/DELETE/etc) imply invalidation of the representations of the target-uri.
Now POST, as it happens, means "do something that hasn't been standardized" -- see Fielding 2009. It's the method that has the fewest semantic constraints.
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. -- RFC 7231
It's perfectly fine for a POST handler to branch based on the contents of the request payload; if you see X, create something, if you see Y delete something else. It's analogous to having two different web forms, with different semantics, that submit to the same target resource.

Creating user record / profile for first time sign in

I use an authentication service Auth0 to allow users to log into my application. The application is a Q&A platform much like stackoverflow. I store a user profile on my server with information such as: 'about me', votes, preferences, etc.
When new user signs in i need to do 1 of 2 things:
For an existing user - retrieve the user profile from my api server
For a new user - create a new profile on the database
After the user signs in, Auth0(the authentication service) will send me some details(unique id, name and email) about the user but it does not indicate whether this is a new user(a sign up) or a existing user(a sign in).
This is not a complex problem but it would be good to understand best practice. I can think of 2 less than ideal ways to deal with this:
**Solution 1 - GET request **
Send a get request to api server passing the unique id
If a record is found return it
Else create new profile on db and return the new profile
This seems incorrect because the GET request should not be writing to the server.
**Solution 2 - One GET and a conditional POST request **
Send a get request to api server passing the unique id
The server checks the db and returns the profile or an error message
If the api server returns an error message send a post request to create a new profile
Else redirect to the home page
This seems inefficient because we need 2 requests to achieve a simple result.
Can anyone shed some light on what's best practice?
There's an extra option. You can use a rule in Auth0 to send a POST to the /users/create endpoint in your API server when it's the first time the user is logging in, assuming both the user database in Auth0 and in your app are up-to-date.
It would look something like this:
[...]
var loginCount = context.stats.loginsCount;
if (loginCount == 1) {
// send POST to your API and create the user
// most likely you'll want to await for response before moving on with the login flow
}
[...]
If, on the other hand, you're referring to proper API design and how to implement a find-or-create endpoint that's RESTful, maybe this answer is useful.
There seems to be a bit of disagreement on the best approach and some interesting subtleties as discussed in this post: REST Lazy Reference Create GET or POST?
Please read the entire post but I lean towards #Cormac Mulhall and #Blake Mitchell answers:
The client wants the current state of the resource from the server. It is not aware this might mean creating a resource and it does not care one jolt that this is the first time anyone has attempted to get this resource before, nor that the server has to create the resource on its end.
The following quote from The RESTful cookbook provided by #Blake Mitchell makes a subtle distinction which also supports Mulhall's view:
What are idempotent and/or safe methods?
Safe methods are HTTP methods that do not modify resources. For instance, using GET or HEAD on a resource URL, should NEVER change the resource. However, this is not completely true. It means: it won't change the resource representation. It is still possible, that safe methods do change things on a server or resource, but this should not reflect in a different representation.
Finally this key distinction is made in Section 9.1.1 of the HTTP specification:
Naturally, it is not possible to ensure that the server does not
generate side-effects as a result of performing a GET request; in
fact, some dynamic resources consider that a feature. The important
distinction here is that the user did not request the side-effects,
so therefore cannot be held accountable for them.
Going back to the initial question, the above seems to support Solution 1 which is to create the profile on the server if it does not already exist.

Look up Envelope by DocumentId?

I'm just getting started with the DocuSign REST API (creating a proof-of-concept integration with my company's product) and am trying to wrap my head around everything. There are a couple things I can't find much info on:
When creating an Envelope, does the documentId matter? I assume if there are multiple documents the documentId for each would need to be different. Is it used anywhere else?
Periodically, I'd like to check the Audit Events for an Envelope. It would be much easier if I could look up the Envelope (or go straight to the Audit Events without looking up the Envelope) with a documentId instead. Is this possible?
Our product already stores documents, and therefore has a documentId - so that is the ID I am using when creating Envelopes. What I'd like to do is, with whatever document I am viewing in our product is check to see if there are any non-completed Envelopes pending. Then I wouldn't need to store any DocuSign related data in our system (i.e. envelopeId).
Can I look up an Envelope by the documentId used to create it?
The documentId is a client defined property and is simply there to help you tag the documents that were used for given envelopes. If you want to track the documents that you're supplying in your envelopes (which it sounds like you are) then you can use it to uniquely identify the underlying docs and if you already have a system that has generated the documentIds then that should make things easier.
No there is not a way to retrieve envelope information through documentId. The best solution is most likely to store a simple table on your side that links documentIds to envelopeIds, then given the documentId you want to search for use the linked envelopeId to retrieve its status.
You should note, though, that there are certain API call limits in place for some API calls and requesting envelope status is one of them. You are not allowed to request status on a given envelope more than 1 once every 15 mins. Instead, the DocuSign Connect module is recommended if you want to track real-time status (DocuSign Connect pushes status out to you as soon as it happens instead of you polling for status every so often).
For more info on API call limits check out the API Best Practices doc in the DocuSign Developer Center under the Go Live section:
https://www.docusign.com/developer-center/go-live/certification

Updating something in REST

Philosophically, I had questions about some examples on how to tackle the following REST scenarios:
1) A user who is signed in wants to 'favorite' someone's blog posting. The user id is a guid and the blog posting is a guid. Should this be a PUT because user/blog exist, or POST because there is no entry in the 'favorites' table?
2) A security row in the DB consists of 10+ properties, but I'd only want to update one part of the entity (# of failed login attempts for a user). What should the call be? Pass the entire data transfer object in JSON? Or just add a new api route for the specific action to update? I.e. a PUT with just one parameter (the # of login attempts) and pass the id of the user.
3) Similar to #2, a user class (consisting of 25+ properties) but I'd only like the user to update a specific part of the class, not the whole thing. Philosophically do I need to pass the entire user object over? Or is it OK to just update one thing. It seems I could get crazy and make lots of specific calls for specific properties, but the reality is I will probably only update 2-3 specific parts of the user (as well as obviously updating the whole thing in other cases). What's the approach here for updating specific parts of an entity in the DB?
Thanks so much
Use a POST if you don't have an ID/UUID yet.
The resource is the security record. Do a PUT on that ID, and pass a block of the properties to be changed.
Ditto (2). You should get whatever parameters will help you identify that record in the DB. If it's unsavory to send these in the POST request and you're doing AJAX, just stash them in the session.
With REST, everything is about updating discrete resources ("nouns"). It's up to you how you want to assign these, but a simple interface that uses verbs ("PUT", "GET", "DELETE", etc..) sensibly, returns relevant HTTP codes, and is easy for others to implement is the best way to go.
So, just ask yourself, "What nouns do I want to give CRUD to, and am I going to exhaust people who wish to consume my API?"

REST: Why URI as Data Container?

I am supposed to make web services for an app and thought I could do a nice job practicing the good practice. As I found out it's using REST. But there is one thing that makes very little sense in it.
Why use URI to pass any variable?
What we did in our last project is use POST only and pass whatever as raw POST data (which was JSON). That's not very RESTful. But it has some advantages. It was quite simple on the client side - I had a general function that takes URI and data as arguments and then it wraps it up and sends it.
Now, if I used proper REST, I would have to pass some data as part of the URI (user ID, for instance). All the other data (username, email and etc.) would have to go as raw data, like we did, I guess. That means I would have to separate user ID and the other data at some point. That's not so bad but still - why?
EDIT
Here is a more detailed example:
Let's say you want to access (GET) and update (POST) user data. You may have a service accessible under /user but what RESTful service would do is accept user's ID as part of the URI (/user/1234). All the other data (name, email and etc) would go to request content (probably as JSON).
What I pose is that it seems useless to make put user id in the URI. If you wanted to update user data - you would send additional data as content anyway. If you wanted to access it - you could use same generic method to request web service.
I know GET gets cached by a browser but I believe you have to cache it manually anyway if you use AJAX (web) or any HTTP client library (other platforms).
From point of scalability - you can always add more services.
You use the URI to identify the resource (user/document/webpage) you want to work with, and pass the related data inside the request.
It has the advantage that web infrastructure components can find out the location of the resource without having any idea how your content is represented. For example, you can use standard caches and load balancers, all they need to know is the URL and headers (which are always represented the same way) Whether you use JSON, protobuf or WAV audio to communicate with your resource is irrelevant.
This will for example let you keep different resources in totally different places, if you send it all as content you won't have the advantage of being able to place the resources in totally different locations, as for example http://cloud.google.com/resource1 and http://cloud.amazon.com/resource2.
All this will allow you to scale massively, which you won't be able to do if you put it all on http://my.url.com/rest and pass all resource info as content.
Re: Your edit
Passing the user id in the URL is the only way to identify the individual resource (user). Remember, it's the user that's the resource, not the "user store".
For example, a cache that caches http://my.url/user won't be much good, since it would return the same cached page for every user. If the cache can work with http://my.url/user/4711, it can cache every user separately. In the same way, a load balancer could know that users 1-5000 are handled by one machine, 5001-10000 by another etc. and make intelligent decisions based on the URL only.
Imagine a RESTful web service as a database.
To get or modify specific object you need to identify it by providing its primary key.
You identify a user by his ID, not his Name+Nickname+e-mail+mother's maiden name.
The information that identifies an object or selects a set of objects goes to the URL. The information that modifies objects should be POSTed to the corresponding URL.