Update property on resource - api

Is there a REST rule or best practice to update/create a specific property on a resource? For example say I have a user resource.
/users (GET) gets all users, POST create a new one, and put /users/(id) updates the user with that id.
Lets say I need to update a status for that person. I could just pass that in the PUT request, but problem is I want to delete the status as well. Usually with PUT I have only been updating the values passed, ie if you put with firstName=Bob I would update that persons firstName but I would not delete his lastName just because it was not passed in. As well as I would not delete status if it was not passed. So I need a way to delete status.
So I was thinking status was just another resource. But a very uncomplicated one.
/users/(id)/status POST to create a new status? Problem I am trying to wrap my head around is that status is just a simple name, like 'away' or 'vacation'. Seems weird to do /users/(id)/status with a body of status=away. Ie status appears in URL and in body, seems wrong. Also with this approach POST and PUT would be identical. Maybe that is ok.
I feel like I have the simple cases of REST down but this one is stumping me.

Typically you would use PUT to create a new resource if you can describe it fully and as though it were a resource location. Use POST (with data) to update any portion of the resource that is hidden. Since status does not identify the resource, I think you should use POST.
Adding example:
POST /users HTTP/1.1
<user id="someID" >
<status>newStatus</status>
</user>

Related

Good practices for designing REST api relations

We currently trying to design some REST api for our webservices. We have two resources, 'record' and 'expedition'. As far as we know, a record can be associated with multiple expeditions, and an expedition can be associated with one record (but not necessarily).
When we create an expedition, and we want to "attach" it to a record, we have come to two solutions :
POST /expeditions?recordId=xxx
POST /records/xxx/expeditions
and a POST /expeditions WS to create expeditions independently.
My colleague suggested the first approach, but I found the second the most usual way to do so. I have not found articles on the web presenting the first approach as a good or bad design.
So, which solution is the good one for you ? Which kind of consideration can help us to choose ?
Thank you.
Which kind of consideration can help us to choose ?
Think about cache-invalidation.
HTTP is about document transfer. We obtain information from the server by asking for a copy of a document; that request might be handled by the server itself, or it might be handled by a cache that has a valid copy of the document.
We send information to a server by proposing edits to documents - POST being the most common method used to do that (via HTML forms).
When an edit is successful, it follows that the previously cached copies of the document are out of date, and we would really prefer that they be replaced by the updated copy.
General purpose cache invalidation is kind of limited; in particular, it doesn't support arbitrary invalidation of documents. Only the target-uri, Location, and Content-Location are invalidated.
Therefore, when we are designing our resource interactions, we want to consider this limitation.
That usually means that the request that we use to change a document should have the same target-uri as the request to read that same document.
(Yes, that means that if we are going to have different kinds of edits to the document, all of the different edits share the same target-uri, and we disambiguate the edit by looking at other parts of the request -- for instance by parsing the body.)
POST /records/xxx/expeditions and a POST /expeditions WS to create expeditions independently.
That's not required - the server is permitted to apply changes to more than one document; HTTP constrains the meaning of the request, but does not constrain the effects.
That said, general purpose caches won't magically know that both documents have been edited. To some degree, part of what you are choosing in your design is which document needs to be refreshed now, and which ones can be out of date for a time (typically until the cached representation reaches its max age).
For the special case where your response to the successful edit is going to be a copy of the updated representation of the resource, you have a little bit more freedom, because use can use the Content-Location header to identify which document we are returning in the response, and that header is automatically invalidated.
POST /foo/bar
...
200 OK
Content-Location: /foo
In this sequence, general purpose headers will invalidated their cached copies of both /foo and /foo/bar.
(of course, there are still issues, in so far as we don't have a mechanism to return both the updated copy of /foo and the updated copy of /bar in a single response. So instead we need to look into other ideas, like server push).
Design the URL paths in a way that the resources can easily be retrieved.
Query string/parameter present in the URL mentioned in the first approach is typically used to locate a resource and perhaps a little counter intuitive to me.
The second approach, perhaps this would work as you are creating an expedition under an associated record xxx i.e. /records/xxx/expeditions. But it could get challenging in a scenario where an expedition is not related to any record.
Another alternative thought here is to link the expedition and record through the payload i.e. have the record id XXX within the POST payload during the "expedition" resource creation. POST /expedition => This operation would return you an expedition id in response as the resource newly gets created. To retrieve the data, you could then use GET /expedition/XXX/record where XXX is the expedition id and you retrieve the record corresponding to XXX. You don't need to mention a record id in this case. You either get a associated record or you don't(in case there is no record tied to the expedition). To retrieve the expedition itself, the URL could be GET /expedition/XXX.

API Blueprint - How to perform a simple UPDATE

I have went through the documentation of Apiary but did not find out how to create a blue print to update a resource.
What I am trying to achieve here is a simple scenario such as having a list of users, being able to list them, retrieve a single user by id, define different attributes for that user, modify one-n attributes of that user (updating that user), and delete that user.
Could someone redirect me to some clear documentation or to a stackoverflow question that I have missed during my research and that would help me achieve this?
I think you have to use PUT or PATCH method for update resource. Look into this blog post here are some examples.

Need help understanding REST API endpoints

I don't quite grok how to sensibly structure a REST (or REST-like) API.
Imagine an API for creating and sending out newsletter emails. You might have the following nouns/resources: newsletters (subject, body, etc.), mailing lists (collections of recipients), and recipients (email addresses and associated data).
So you could use PUT to create a resource and be returned its ID:
/newsletter
/list
/user
You could obtain information on a resource using GET:
/newsletter/[id]
/list/[id]
/user/[id]
You can update an existing resource using PATCH (or should this be POST?):
/newsletter/[id]
/list/[id]
/user/[id]
You can delete a resource using DELETE:
/newsletter/[id]
/list/[id]
/user/[id]
Is the above correct?
What endpoints are sensible for actions like sending a newsletter to a list, adding a user to a list?
Does the following make sense, and is it RESTfull?
/newsletter/[newsletter_id]/send/[mailinglist_id]
/list/[list_id]/add/[user_id]
/list/[list_id]/remove/[user_id]
Is it redundant or unhelpful to have list/[id]/add/[id] and list/[id]/remove/[id] endpoints for lists, when users could be added or removed via PATCH at /list/[id] ?
What about searching for a users' ID via a property like email address or name? Or getting a list via an identifier like its name or when it was created?
You pretty much nailed it, except with the /list/[list_id]/add/[user_id] and /list/[list_id]/remove[user_id], because you have verbs in the URL - that is the purpose of the HTTP methods. Change them to, for example:
PUT (or POST) to /list/[list_id]/users/ for adding a user to the list
and
DELETE to /list/[list_id]/users/[user_id]
For search, I'd go with parameterized url for the list of resources, like:
/newsletter/?name=dfjkhskdfh
These verbs are often confused:
To create an entity you use POST
To update - PUT
These things could be treated in the following way:
POST /newsletters/[newsletter_id]/mailinglists/[mailinglist_id]/mailingfacts - performs sending the letters, it's like adding a fact of mailing to the collection
/lists/[list_id]/[user_id] - adds a user to the list
/lists/[list_id]/[user_id] - deletes the user from the list.
Is it redundant or unhelpful to have list/[id]/add/[id] and list/[id]/remove/[id] endpoints for lists, when users could be added or removed via PATCH at /list/[id] ?
It is bad/unhelpful. One of the ideas of REST is that the end points are resources and not a Remote Procedure Call (RPC). add or remove is suggesting a procedure to call.
Further GET requests should be side-effect free, that is, they don't do any updates. Further Roy Fielding explains GET as:
retrieval of information that should be a representation of some resource
So GET is only for retrieval, not for sending data (i.e. which user to add/remove).
The other very dangerous problem with list/[id]/remove/[id] is that if a spider or your test framework is going around your site it could start deleting items.

When should an object be included as a member of another object, and when should it always standalone?

An example problem:
On Stack Overflow, a question page shows a number of different answers. In displaying these answers, the site also gives information about the author of the answer. This means that although the number of badges a given user has has nothing to do with an answer in and of itself, that data still needs to be retrieved in order to display the page.
From what I can see, there are three different ways to go about pulling this view data in a model:
A Post object could include a full User object as a member. The view would then access the user like this: $post->user->getReputation(). This seems cleaner, since a Controller could just request the posts and be done with it, but yet inefficient since a Post probably doesn't always need a full-blown User. I suppose it works well enough if the User object is relatively light, which it probably would be. The problem would then be that you would need to duplicate User retrieval code as part of the Post retrieval query.
The Post object could hold just an ID for a User. When the Post, or Posts, are returned to the Controller, the Controller could then extract the unique User IDs from the returned set and pass them to a User factory. The returned User objects would then be passed along with the original Posts set to the View as a separate collection. The view could then grab user info using something like $users[$post->getUserId()]->getReputation().
A hybrid approach: Include the User object inside the Post object, but have the unique id extraction and User retrieval as part of the Post retrieval method. i.e. Post::getPosts() would grab all relevant posts and convert them to objects with null User members, then it'd extract all user ids and pass them to User::getUsers(), then assign the Users to the relevant Posts before returning the set of Posts to the caller.
I guess what I'm getting at is, how do I know when an object needs to contain another object fundamentally? Is it unclean/a code smell to instead have such related objects returned separately, with neither object knowing the other has been retrieved. I'm leaning towards the separate retrieval concept - it seems the most efficient - but it really does feel like they're too related for that to make sense.
There is also a solution in between 1 and 2. You can have a lazy loading proxy for the user class. With this solution you can have best of both worlds because the proxy is interchangeable with the real thing so depending on the situation you can have the object itself or the proxy.
Edit:
I'll try to explain this with an example.
Say that you have a view where you don't need user info, then you can instruct/configure your post factory to use the lazy proxy (see wikipedia)for the user which will only contain an ID. So no access to users is needed.
In another view you occasionally need to access user info but only for some posts, here again you instruct/configure your factory to include the lazy proxy for the user.
But when you actually need access to the user info, you can access the proxy object that will then load the actual user object and redirect messages to it.
In yet another view you need both post and user info, so here you instruct your post factory to use actual user objects.
It seems to me that this is another case of dependency injection. A general enough idea that could help you.
DEPENDENCY INJECTION WIKI
Read something about the Inversion Of Control also.
why not add optional member to model to know informations?? you can ignore when you don't need and can use when you do need.

Simple mod_rewrite rule.....?

I have a edit page that looks at record_id's in the url.. I don't want the user to see any record id, that way they can't replace it with another and edit another record....
Anyways, my url is like:
http://www.mywebsite.com/folder/folder_detail_edit.php?recordID=3980
I would like it to just display:
http://www.mywebsite.com/folder/folder_detail_edit.php
Is this possible regardless of the recordID???
You should use the http post method to send this data to the server, this way, it won't be visible in the url.
Take a look here
The central problem is not that the record ID is visible and thus can be replaced but that your application allows your users to modify all records. That’s an authorization problem. And hiding the ID does not solve that since the record has to be identified somehow.
You should better implement some authorization mechanism so that your users can only access and modify those records that they are allowed to.