What is the recommended/effective request payload for a REST PUT method? - rest

I see two types of examples in various places. One uses form fields like
curl -X PUT -d "phone=123.456.7890" "http://127.0.0.1/services/rest/user/123"
and the other uses an XML content like (some variation of) this
echo "<user><id>123</id><phone>123.456.7890</phone></user>" | curl -X PUT -d #- "http://127.0.0.1/services/rest/user/"
It seems like using the form fields has the advantage of brevity and clearly identifying the client's intent by targeting just the modified fields, but makes it awkward to address "deeper" metadata.
Using the XML content has an advantage of being more complete, but the disadvantage of the overhead of figuring out which field the client is actually modifying (assuming that they send back the entire resource with small modifications).
Is there a best practice, or even a more-common practice?

It could be something like JSON(P)? (I'm not sure about exact syntax):
$ echo '{user: {id: 123, phone: 123.456.7890}}' |\
> curl -X PUT -d #- 'http://127.0.0.1/services/rest/user/'
Or
$ echo '{phone: 123.456.7890}' |\
> curl -X PUT -d #- 'http://127.0.0.1/services/rest/user/123.json'

In the second example URL does not refer to a specific resource, so IMHO it's not RESTful.
If you fix that, the choice comes down to form and XML encoding.
If you need structured and extensible data, then XML might be useful:
<phone type="work, mobile"><num>555-555</num><ext>123</ext></phone>
but not neccessary:
phone=555-555&phone-ext=123&phone-type=work&phone-type=mobile
Lots of API users may get XML encoding wrong, have trouble grasping namespace indirection, so form encoding might be better for wide audience.

Good question! I don't know of a specific best practice or common practice. But I do want to point out that the question isn't really about form fields or XML, it's about partial representations vs. full representations. You've succinctly described the practical differences between them. One aspect of the question is who has the responsibility to determine what has changed: the client or the server.
A hybrid option would be some kind of format wherein a client could specify what exactly has changed, using some syntax to point to "deeper" metadata, such as XPath or JSONpath, along with the new value.

Related

Bitbucket REST API does not handle second query parameter

I want to find out the changed files between two given commits/branches/tags using the Bitbucket Rest API.
I tried to use the diff command from here
curl -u USER:PASSWORD https://REPO-URL/rest/api/latest/projects/PROJECT/repos/REPO/compare/diff?from=COMMITHASH1&to=COMMITHASH2
where CAPITAL words are place holders for actual values I cannot post here.
The result of the request is always something like
The command "to" is spelled wrong or cannot be found
(the original result is in German, so that might be the translation).
However, if I switch the query parameters like .../diff?to=...&from=..., it says that the command from is unknown. I also tried other similar diff queries like .../compare/changes?from=...&to=... or .../diff?since=...&until=..., but the result was similar as mentioned above. Also giving branch names instead of commit-hashs showed no result.
Therefore, my assumption was that the second query parameter cannot be handled correctly by the API.
Other basic queries on the API like .../branches work fine, so authentication or whatever is no problem.
What am I doing wrong? Do I need to wrap the commit-hashs into "" or something like that?
Thank you very much!
PS: As the repository is commercially used, I cannot give you the actual url, user or password to try for yourself.

which type of request is used for the `delete` button in the REST context?

I am creating a REST API for the Order screen. I have methods:
GET /api/orders
GET /api/orders/{orderId}
I have some buttons on the Order page and I created few endpoints for that:
PATCH /api/order/buttons/mark-as-read
PATCH /api/order/buttons/change-status
Now I need to add the delete button. But I don't understand how to do that. I have 2 options:
DELETE /api/orders/{orderId} - but I should send 2 additional parameters in this request
PATCH /api/order/buttons/delete - I can send my DTO in the body, but it is not a REST approach.
I want to understand which type of request is used for the delete button in the REST context?
PATCH /api/order/buttons/mark-as-read
PATCH /api/order/buttons/change-status
These are a bit strange. PATCH is a method with remote authoring semantics; it implies that you are making a change to the resource identified by the effective target URI.
But that doesn't seem to be the case here; if you are expecting to apply the changes to the document identified by /api/orders/{orderId}, then that should be the target URI, not some other resource.
PATCH /api/orders/1
Content-Type: text/plain
Please mark this order as read.
PATCH /api/orders/1
Content-Type: text/plain
Please change the status of this order to FULFILLED
Of course, we don't normally use "text/plain" and statements that require a human being to interpret, but instead use a patch document format (example: application/json-patch+json) that a machine can be taught to interpret.
I want to understand which type of request is used for the delete button in the REST context?
If the semantics of "delete" belong to the Orders domain (for instance, if it is a button that signals a desire to cancel an order) then you should be using PUT or PATCH (if you are communicating by passing updated representations of the resource) or POST (if you are sending instructions that the server will interpret).
The heuristic to consider: how would you do this on a plain HTML page? Presumably you would have a "cancel my order" form, with input controls to collect information from the user, and possibly some hidden fields. When the user submits the form, the browser would use the form data and HTML's form processing rules to create an application/x-www-form-urlencoded representation of the information, and would then POST that information to the resource identified by the form action.
The form action could be anything; you could use /api/orders/1/cancel, analogous to your mark-as-read and change-status design; but if you can use the identifier of the order (which is to say, the resource that you are changing), then you get the advantages of standardized cache invalidation for free.
It's normal for a single message handler, which has a single responsibility in the transfer of documents over a network domain, ex POST /api/orders/{orderId}, to interpret the payload and select one of multiple handlers (change-status, mark-as-read, cancel) in your domain.
you offer to use something like this: PATCH /api/orders/{orderId} and OrderUpdatesDto as JSON string in the request body?
Sort of.
There are three dials here: which effective request URI to use, which payload to use, which method to use.
Because I would want to take advantage of cache invalidation, I'm going to look for designs that use: /api/order/{orderId} as the effective request URI, because that's the URI for the responses that I want to invalidate.
It's fine to use something like a JSON representation of an OrderUpdate message/command/DTO as the payload of the request. But that's not really a good match for remote authoring. So instead of PATCH, I would use POST
POST /api/orders/1 HTTP/1.1
Content-Type: application/prs.pavel-orderupdate+json
{...}
But you can instead decide to support a remote authoring interface, meaning that the client just edits their local copy of /api/order/1 and then tells you what changes they made.
That's the case where both PUT (send back the entire document) and PATCH (send back a bunch of edits) can make sense. If GET /api/orders/1 returns a JSON document, then I'm going to look into whether or not I can support one of the general purpose JSON patch document formats; JSON Patch or JSON Merge Patch or something along those lines.
Of course, it can be really hard to get from "changes to a document" to a message that will be meaningful to a non-anemic domain. There are reasons that we might prefer supporting a task based experience, but sending a task centric DTO is not a good fit for PUT/PATCH if you also want caching to work the way I've described above.

How do I reassign users in an experiment bucket that has been closed in Intuit’s Wasabi?

Initially I had two buckets, “control group” and “treatment”. After running the experiment for a while (users got assigned to both buckets), I closed the “control group” bucket, and made the “treatment” bucket user allocation to 100%. However, I need to reassign all users who are in the “control group” bucket to the “treatment” bucket. How do I do that?
There is currently no way to do this easily.
The "just do it for all" method:
To assign all users to the same bucket, you can use this script on your assignments.csv (which can be downloaded via the UI):
for i in $( tail -n+2 assignments.csv | awk '{split($0,a,"\t");print a[2];}' ); do curl -X PUT -d '{"assignment": "NEW_BUCKET_NAME", "overwrite": true}' -H "Content-Type: application/json" http://HOST:PORT/api/v1/assignments/applications/APPNAME/experiments/EXPERIMENTLABEL/users/$i ; done
If you don't want the output to scroll around, you can add > output.log to store it to a log or >/dev/null to completely ignore it.
Note: there is no simple going back and depending on the number of assignments this will take a while. I will check if there are better methods, but I am not aware of any yet.
The "just do it when needed" method:
If you are able to change your production code, you can also just use the PUT assignment for each user individually when they come back to your website. Just use a PUT to:
http://HOST:PORT/api/v1/assignments/applications/APPLICATION/experiments/EXPERIMENT/users/USER
and make sure to send the header Content-Type: application/json and as the body: {"assignment": "NEW_BUCKET_NAME", "overwrite": true}.
(Since I am also one of the developers: I suggest you create an issue for this use case on the wasabi github repository, so we can easily track this issue and you can help us developing a solution for this problem.)

How to create and implement a pixel tracking code

OK, here's a goal I've been looking for a while.
As it's known, most advertising and analytics companies use a so called "pixel" code in order to track websites views, transactions, conversion etc.
I do have a general idea on how it works, the problem is how to implement it. The tracking codes consist from few parts.
The tracking code itself.
This is the code that the users inserts on his webpage in the <head> section. The main goal of this code is to set some customer specific variables and to call the *.js file.
*.js file.
This file holds all the magic of CRUD (create/read/update/delete) cookies, track user's events and interaction with the webpage.
The pixel code.
This is an <img> tag with the src atribute pointing to an image *.gif (for example) file that takes all the parameters collected on the page, and stores them in the database.
Example:
WordPress pixel code: <img id="wpstats" src="http://stats.wordpress.com/g.gif?host=www.hostname.com&list_of_cookies_value_pairs;" alt="">
Google Analitycs:
http://www.google-analytics.com/__utm.gif?utmwv=4&utmn=769876874&etc
Now, it's obvious that the *.gif request has to reach a server side scripting language in order to read the parameters data and store them in a db.
Does anyone have an idea how to implement this in Zend?
UPDATE
Another thing I'm interested in is: How to avoid the user's browser to load the cached *.gif ? Will a random parameter value do the trick? Example: src="pixel.gif?nocache=random_number" where the nocache parameter value will be different on every request.
As Zend is built using PHP, it might be worth reading the following question and answer: Developing a tracking pixel.
In addition to this answer and as you're looking for a way of avoiding caching the tracking image, the easiest way of doing this is to append a unique/random string to it, which is generated at runtime.
For example, server-side and with the creation of each image, you might add a random URL id:
<?php
// Generate random id of min/max length
$rand_id = rand(8, 8);
// Echo the image and append a random string
echo "<img src='pixel.php?a=".$vara."&b=".$varb."&rand=".$rand_id."'>";
?>
Just adding my 2 cents to this thread because I think an important, and frequently used, option is missing: you don't necessarily need a scripting language to capture the request. A more efficient approach is to use the web server access log (like apache access log for instance) to log the request and then handle that log with whatever tools you see fit, like ELK stack for instance.
This makes serving the requests much lighter because no scripting language is loaded to prepare the response, just native apache response, which is typically much more efficient.
First of all, the *.gif doesn't need to be that file type, the only thing that is of interest is the Content-Type http header. Set that to image/gif (or any other, appropiate type) in the beginning, execute your code and render some sort of image to the response body.
Well, all of the above codes are correct and is good but to be certain, the guy above mention "g.gif"
You can just add a simple php code to write to an sql or fwrite("file.txt",$opened)
where var $opened serves as the counter++ if someone opened your mail... then save it as "g.gif"
TO DO all of this just add these:
<Files "/thisdirectory">
AddType application/x-httpd-php .gif
</Files>
to your ".htaccess" file but be sure to make a new directory for that g.gif or whatever.gif where the directory only contains g.gif and .htaccess

REST API versioning when using Atom for resource collections

I know this is something that has been discussed over and over, and I have done extensive research to get where I am so far, but can't seem to get over the final hurdle.
I am designing a custom REST api for our application, and have decided that I would like to version using media types e.g. application/vnd.mycompany.resource.v2+xml. I realise the pro's and con's of this model and it seems to weigh up the most flexible.
Hence my GET would look as follows:
=== REQUEST ===>
GET /workspaces/123/contacts?firstName=Neil&accessID=789264&timestamp=1317611 HTTP/1.1
Accept: application/vnd.mycompany.contact-v2+xml
<== RESPONSE ===
HTTP/1.1 200 OK
Content-Type: application/vnd.mycompany.contact-v2+xml
<contact>
<name>Neil Armstrong</name>
<mobile>+61456838435</mobile>
<email>neil.armstrong#space.com</email>
</contact>
The problem is that I would like to use Atom feeds and entrys to represent my resource collections. This way I can harness the searching and pagination of Atom without this infected my resources or API structure.
If I use Atom for my requests, my request structure now looks like:
=== REQUEST ===>
GET /workspaces/123/contacts HTTP/1.1
Accept: application/atom+xml; type=feed;
<== RESPONSE ===
HTTP/1.1 200 OK
Content-Type: application/atom+xml; type=feed;
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Contacts Feed</title>
<link rel="self" href="https://api.mycompany.com/workspaces/contacts"/>
<updated>2011-11-13T18:30:02Z</updated>
...
<entry>
<title>Neil Armstrong</title>
...
<content type="application/vnd.mycompany.contact-v2+xml">
<contact>
<name>Neil Armstrong</name>
<mobile>+61456838435</mobile>
<email>neil.armstrong#space.com</email>
</contact>
</content>
</entry>
</feed>
Using Atom to represent my collections of resources, I lose the ability to version using media types. As the media type is now hidden within the content of the Atom entry.
<content type="application/vnd.mycompany.contact-v2+xml">
What is the best practice for determining the media type version of my resource, while still utilising the power of Atom for Resource collection management?
My thinking is that I could pass it through the ACCEPT header e.g.
Accept: application/atom+xml; type=feed; version=1.0
But then this is confusing as you are asking for version 1.0 of the Atom feed, not the resource itself...
Any help would be really appreciated!!
The problem is that IMHO you're misusing the media types.
Media types give you information on the STRUCTURE of the actual payload, but not the SEMANTICS of the payload. "I know this is an XHTML page, but I don't know if it's a blog post or a item on Amazon." By being an XHTML page, you know how to get the component parts out of the payload and ask interesting questions, but interpretation of the payload is not part of the media type.
Consider an example, paraphrased from an example of Roy Fielding, sending a 10,000 bit array as a GIF file that's 100x100 pixels. GIF, as "everyone knows" is used for sending pictures, but it's really simpler than that. It's a mechanism for sending structured binary that just-happen to most-of-the-time be images. So, in this case of using it to send a 10,000 bit array (perhaps represented as a gray scale image of 00 and FF), you get the benefit of a common decoder (GIF), GIFs built in compression, etc.
But, in this case, it's not a picture. You can show it as a picture, but it's a meaningless picture. The classic semantic of it being used for the picture scenario is not relevant in this case. The benefit is the ubiquity of the the format.
Another example was years ago an engineer was doing radar studies. So, he would take the 3-view drawings of aircraft you would find in books and such, and he would encode them using a tablet in to AutoCAD drawings. The DWG format was well documented, and he had code to read them. What he wanted was the coordinates and measurements from the specific aircraft.
So, in the end he had a bunch of "meaningless" AutoCAD files with nothing but a bunch of lines in it that "made no sense". But in fact they were chock full of good information for his domain. The DWG file was the media-type, but these weren't "CAD drawings". (Can you say "spontaneous reuse"?)
It's fine to version something via media-type, but that's only relevant if the media-type is in fact changing. ATOM, as you noted, isn't changing, or at least it's not changing under your control, and you may choose not to support the new version if/when it does change. But ATOM is not changing because how it represents its information, how that information is encoded, is not changing. The information may well change, in fact it changes all the time. Every ATOM feed is different with different information. MOST have similar semantics (blog feeds), but many do not (for example, perhaps your scenario).
But how you will parse and get information out of the ATOM feed will not change. And that's what the media type represents. An encoding of information, not the information itself.
So, if you want to detect versioning, then check within your payload. Inspect it. You KNOW that for V1 of your data where, for example, the invoice number is (perhaps it's at invoice/inv_no in XPATH). If the invoice is NOT there, then what do you do? You a) look some other well known place (i.e. V2), or, b) you throw an error ("Whatever this is, it's not an invoice!"). You would have to do that no matter what, because you could be getting anything, regardless of what the version says, or the media type says, or what anything else says.
You can make your payloads forward compatible to be resistant to breaking change, then version is a matter of making use of all the information you can see. If you get A and B, then while you'd like to have C and D as well, the clients can get by with the more limited information. Of if the clients see C and D, they would know to ignore A and B, as that data is deprecated. Same with the server. If something is sending A and B, it's implied to be an older processing model than if they sent along C and D.
You can version through rel names "order" vs "order_2", old clients only know to use "order", new clients know to use "order_2" and follow that link instead.
Or you simply include a version identifier in the payload, that's an easy check as well (especially since it's early in your design).
There are a lot of ways to manage the versioning, but the media type really shouldn't be the mechanism. That's why this really isn't a "problem" with ATOM. So, it's a matter of perspective.
I have another discussion about the Accept header over here: REST API having same object, but light
This (IMHO) unrelated to your versioning issue, but it's an example of extended media-types. But that's only my perception of why and how most folks want "versioning". A case could be made this case is the same thing, but most folks associate versioning with services, not simply data representations, which this other post was mostly about.
In the end, either your client and/or server are flexible enough to handle versioned data or they're not. They will (mostly, they are computers after all. Deterministic my heinie...) do what they're told. A simple rule of "ignore stuff that you don't know" can take you quite far in terms of versioning without ever changing a v1 to a v2, regardless of your encoding. Likewise "work with what you have" is a nice rule for a flexible, tolerant server. If you have problems in either case, that's what errors, logs, operators, and 24hr pagers are for, and you need those anyway.