Should RESTful 'PATCH' operation return something? - web-services

I am struggling what is the best practice for PATCH method.
I see couple of possibilities:
Return HTTP status code 200 OK with updated object.
Return HTTP status code 204 No Content.
What would be the best one?

The specification states:
The 204 response code is used because the response does not carry a
message body (which a response with the 200 code would have). Note
that other success codes could be used as well.
Which just means you may decide to return a body or not, the response codes should then be 200 or 204 respectively. Neither is better or worse than the other. You may find that it is practical to just return the changed content, so the client does not have to make a new request to get the new content.
Note: using the PATCH is quite tricky, as you must define a mime-type for applying change-sets to your resource. This may not be what you want. More often than not, PATCH can be solved by just creating a new resource that should have been a resource anyway.

Related

How to set default response for MockWebServer?

MockWebServer is awesome library, but there is one thing that is surprisingly hard to do: set default response.
To be specific: I want to have ability to set response that is returned if no response was specified using server.enqueue(response).
I would like to be able to do something like:
server.setDefaultResponse(okResponse)
server.enqueue(customResponse)
And then when my tests call server twice (or more), every response after the first one would be okResponse.
When tests get more complicated and multiple calls to server are needed, sometimes specifying every single response (often simple 200 OK) is tedious and pollutes tests.
Is there any simpler way to do this than creating your own Dispatcher? Creating it properly (with support for multiple responses) sounds like overkill for such a small thing.
There is improvement that can be done in comparison to implementing your own Dispatcher. When looking at MockWebServer implementation I found that its default dispatcher is QueueDispatcher.
And it has some very handy methods, like:
public void setFailFast(boolean failFast)
public void setFailFast(MockResponse failFastResponse)
setFailFast(true) sets server to "fail fast" mode i.e. if no response in enqueued, it doesn't wait, just returns HTTP 404 response immediately.
setFailFast(okResponse) sets response to return in "fail fast" mode, which exactly answers this question.
The problem is, you don't have direct access to dispatcher field in MockWebServer, so what you need to do is set your own instance of QueueDispatcher and then set default response (or "fail fast" response) on it, like that:
val dispatcher = QueueDispatcher()
dispatcher.setFailFast(okResponse)
server.setDispatcher(dispatcher)

GET request with body timing out with URLSession and Alamofire

I'm working with a slightly unconventional API that is expecting a JSON body with a GET request and I have no control over this. Unfortunately, every time I attempt to make the request, it seems to completely disappear and never make it to the API. I originally wrote the request using a standard URLSession and then switched to try Alamofire in an attempt to fix it but ended with the same result. My request looks like this:
Alamofire.request("http://192.168.1.1:8000/connect/", method: .get, parameters: ["test": "test"], encoding: JSONEncoding.default)
.responseJSON { response in
let body = response.request?.httpBody
guard response.result.isSuccess else {
onCompletion(nil)
return
}
onCompletion(response.result.value as! [String : Any]?)
}
This exact code works for a different request where there is no JSON in the body, but seemingly the moment I add it, it just times out. This has already been discussed on the alamofire github repo (https://github.com/Alamofire/Alamofire/issues/1819) but the final comment with what should be working code isn't really any different to mine, so doesn't provide any help, nor do the other linked issues.
Printing the request with debugPrint gives me this curl command
$ curl -i \
-H "Content-Type: application/json" \
-d "{\"test\":\"test\"}" \
"http://192.168.1.1:8000/connect/"
Which is missing the -X GET flag, but when I add that in, the request works as expected and the server responds, so I know the API itself is working and is happy processing the JSON in the body, so I'm at a loss as to what's going on.
I've installed Timberjack to attempt to trace things, which didn't give me any more info at all, just what I already knew
Request: GET http://192.168.1.1:8000/connect/
Headers: [
Content-Type : application/json
Content-Length : 24
]
Although I'm not sure if it's supposed to be showing me the body as well which it isn't?
In both cases (URLSession and Alamofire) the request gives the following output which I don't see at any other time:
2017-01-22 23:31:09.797453 my-app[3755:1349066] [] nw_endpoint_flow_service_writes [2 192.168.1.1:8000 ready socket-flow (satisfied)] Write request has 4294967295 frame count, 0 byte count
2017-01-22 23:32:04.484182 my-app[3755:1349066] [] __tcp_connection_write_eof_block_invoke Write close callback received error: [89] Operation canceled
Anyone have any ideas on what's going on as I'm completely at a loss at this point.
Update
I've done some more digging. If I change the endpoint to https://httpbin.org/get then the request goes through just fine and I get a response. Whilst this kind of suggests the API server is refusing to process the request, it's still working with the cURL command so that can't really be the issue.
I also forgot to mention (although not sure it should make a difference) that the API I'm trying to communicate with is connected via an ad-hoc wifi. Other requests to it work just fine though so I can definitely communicate with it.
Update 2
So I've been able to switch the server to using POST instead of GET and unsurprisingly it now works, however I would still love to know of a solution to the original problem
URLSession and CFHTTPMessage cannot send a message body for a GET request. They send the content length for the body, but do not send the body itself. This results in a timeout.
In order to resolve this issue I've used libcurl to handle the GET requests which have a message body to my project. I use URLSession everywhere else. When you add a body to a request using libcurl it changes the request to a POST, but that can be changed back to a GET after setting the body and before submitting the request.

Reading Jetty Server Request body without making it null

I have a Jetty.Server.Request object, which is an HTTP request whose body I need to use in multiple methods.
I access the body's contents like so -
String contents = baseRequest.getReader().readLine();
However, this seems to remove the body from the HTTP request. If I then try to access it again like so -
String contents2 = baseRequest.getReader().readLine();
contents2 will be null.
How can I read the body of the request object without affecting the request?
Per the Servlet spec, the stream is only available once.
Make a copy of it yourself (either to memory, or to disk for later reading)
This is by design, as many request bodies can by quite large and there simply wouldn't be enough memory to handle rereads in a sane way.
Be sure you check out the prior answers for this:
Http Servlet request lose params from POST body after read it once
As those answer demonstrate a few ways to accomplish multiple reads of the same request body.

eBay API returns JSON when text/plain is specified in header

I'm looking for some perspective. I'm entirely new to API programming. I've found that calling eBay's GeteBayTime method is correctly returning JSON but with a header of text/plain;charset=utf-8, not application/json. Is this an eBay bug, just average API weirdness, acceptable in some way or what? Could it be an error on my part? I'm using C++ Rest SDK for client API access.
The solution, for those who face the same issue, is to change the response header using set_content_type():
if (response.status_code() == status_codes::OK)
{
response.headers().set_content_type(L"application/json");
return response.extract_json();
}
The actual request uses:
http://open.api.sandbox.ebay.com/shopping?callname=GeteBayTime&responseencoding=JSON&appid=<my appid>&siteid=0&version=713
I received a good response at https://casablanca.codeplex.com/discussions/470633. I believe there's more room for discussion. Until then, this will be the standing answer.

Error with Flex HTTPService and Django, even though POST is successful

(This is the first time I've done this actually.)
<mx:HTTPService id="post_update" method="POST" result="{Dumper.info('bye')}"/>
The result handler above is just for debugging purposes, but its never hit, even though what I'm uploading via POST...
post_update.url = getPath(parentDocument.url)+"update";
post_update.send(new_sel);
...is received and handled successfully by my Django view:
def wc_post(request) :
request.session['wc'] = request.POST
return http.HttpResponse("<ok/>", mimetype="text/xml")
As far as what I'm sending back from Django, I'm following the guidelines here:
Sending Images From Flex to a Server
I just don't want it to generate an error on the Flex side considering Django is actually receiving and processing the data. Any help appreciated. Can't remember the text of the error in Flex at the moment.
UPDATE: new_sel (what I'm posting from Flex) is just a Flex Object, with various text fields.
UPDATE: various error messages from event.message (in fault handler):
faultCode = "Server.Error.Request"
faultString = "HTTP request error"; DSStatusCode = 500; errorID = 2032; type = "ioError"
This is more grasping at straws than answers, but do I have to send a particular type of header back from Django- the default sent by Django includes a 200 success status code, and the response I was sending of "<ok/>" with mime type of "text/xml" was following the example exactly that I provided from that other source.
And also the url I'm sending the POST to is localhost:8000/wr_view1/wr_webcube/update, and I previously successfully did a GET to localhost:8000/wr_view1/wr_webcube/webcube.xml, and despite the .xml extension in the case of GET, it was still being handled by Django (and without errors in Flex). In the case of this POST, once again, the data is actually succesfully sent and handled by Django, but Flex is returning Error 2032, which I found out can mean numerous different things including cross domain issues, but don't see how that's the case here.
Just had to return HttpResponse("ok") Didn't like it being sent as xml for some reason. So much ado about nothing I guess.