How to include Zumo API version header in rest client - web-services

I have an Azure Mobile App backend working web service. I am trying to carry out basic crud operations. I understand that you can use a url like myapp/tables/object?zumo-api-version=2.0.0 and this works fine when I am getting data. However, when I want to put, delete etc it requires an id. If I type myapp/tables/object/dsjkfhsdjkfjsdfjkkdjf?zumo-api-version=2.0.0 for example where the string is the id I can carry out the operation. Similarly, if I enter an id in Swagger, I can also carry out the put operation. However, I am unsure as to how to go about adding the zumo-api-version details on the client side. How can I include the zumo version header in my project?

See Header Specification here:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-client-and-server-versioning/
The key ZUMO-API-VERSION may be specified in either the HTTP header or the query string. The value is a version string in the form x.y.z.
For example:
GET https://service.azurewebsites.net/tables/TodoItem
HEADERS: ZUMO-API-VERSION: 2.0.0
POST https://service.azurewebsites.net/tables/TodoItem?ZUMO-API-VERSION=2.0.0
So you could do:
$ curl -sv -H "ZUMO-API-VERSION: 2.0.0" \
http://{mobileapp}.azurewebsites.net/tables/todoitem
> GET /tables/todoitem HTTP/1.1
> Host: {mobileapp}.azurewebsites.net
> User-Agent: curl/7.49.1
> Accept: */*
> ZUMO-API-VERSION: 2.0.0
>
< HTTP/1.1 200 OK
[...]
[{
"id":"40b996d6-ec7f-4188-a310-0f02808e7093",
"createdAt":"2016-08-31T11:30:11.955Z",
"updatedAt":"2016-08-31T11:30:11.971Z",
"version":"AAAAAAAAG5s=",
"deleted":false,
"Yo_mobileapp":"Sup"
}]
Note ZUMO-API-VERSION: 2.0.0 passed in as Header.
If you're asking "Which is better?", there's no better. They do the same thing. That being said, it's probably easier and cleaner to send a Header for most use cases.

Related

upload data with HTTP method POST or PUT

I'm working with STM32-microcontroller and C-languege and want to send to and receive the data from my website. I can receive the .txt file with the "GET" method from website via this code:
static const char http_request[] = "GET "WEBSITE_SUB_ADDRESS" HTTP/1.1\r\nHost: "WEBSITE_ADDRESS"\r\n\r\n";
net_sock_send(socket, (uint8_t *) http_request, len);
net_sock_recv(socket, (uint8_t *) buffer + read, NET_BUF_SIZE - read);
Now I want to send or upload the data to the website in a file with http-method (POST or PUT, ...). How can I do it?
You first need to decide if you want to use POST or PUT.
The PUT method completely replaces whatever currently exists at the target URL with something else. With this method, you can create a new resource or overwrite an existing one given you know the exact Request-URI. ...In short, the PUT method is used to create or overwrite a resource at a particular URL that is known by the client.
The HTTP POST method is used to send user-generated data to the web server. For example, a POST method is used when a user comments on a forum or if they upload a profile picture. A POST method should also be used if you do not know the specific URL of where your newly created resource should reside. ...In short, the POST method should be used to create a subordinate (or child) of the resource identified by the Request-URI.
from https://www.keycdn.com/support/put-vs-post
While connected to the server you would send a HTTP header just as you have done with the GET request that would look somthing like this:
POST /test HTTP/1.1\r\n
Host: www.myServer.com\r\n
Content-Type: text/plain\r\n
Content-Lenght: 8\r\n
Accept: */*\r\n
\r\n
someData
You might also want to check if the server recived the message by looking at the header that is sent back to you, it should include HTTP/1.1 200 OK.
Edit: to get it into a file try /test/mytext.txt but i dont have a way of testing if this works
A good place to test the request is Post Test Server V2. hope this helps
#Flynn Harrison
I tested your method as follows:
static const char http_request[] = "POST "SUB_ADDRESS" HTTP/1.1\r\n"
"Host: "HOST_ADDRESS"\r\n\r\n"
"Content-Type: text/plain\r\n"
"Content-Lenght: 13\r\n"
"Accept: */*\r\n"
"\r\n"
"Data for Write Test";
and then:
net_sock_setopt(socket, "tls_server_name", (uint8_t*)HOST_ADDRESS, sizeof(HOST_ADDRESS));
net_sock_open(socket, HOST_ADDRESS, TIME_SOURCE_HTTP_PORT, 0);
net_sock_send(socket, (uint8_t *) http_request, len);
net_sock_recv(socket, (uint8_t *) buffer + read, NET_BUF_SIZE - read);
When I tried "/test.txt" at SUB_ADDRESS, I get the HTTP / 1.1 200 OK message but immediately after receiving the file contents, in the same buffer, I receive the HTTP / 1.1 400 Bad Request message and I do not see any changes to the file. My response from server is as follows:
HTTP/1.1 200 OK
.
.
.
This is a Test.... (Text-File Content)
HTTP/1.1 400 Bad Request\r\nDate: Fri, 09 Aug 2019 09:03:56
.
.
.
In the site you mentioned, the POST method works well but its mechanism is not clear which I can use. I tried to test the POST method with this site and my device but got error "411 Length Required".

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.

soap connector with access token from header

I'm using the loopback-connector-soap and can pass my access token in like this:
var ds = loopback.createDataSource('soap',
{
...
,soapHeaders: ["..."+ token +"..."]
});
I'm putting a REST layer on top of this and I got it working. But 3rd parties will be hitting this API, so what I really need is to allow the third party to pass their token in via the header when they hit the REST route:
Authorization: Bearer _token_
The app will then place their token in the soap header. Does loopback's soap-connector allow for this scenario?
Things to try:
The loopback token module can be instructed to look for values in headers that you specify: http://apidocs.strongloop.com/loopback/#loopback-token
app.use(loopback.token({
cookies: ['foo-auth'],
headers: ['foo-auth', 'X-Foo-Auth'],
params: ['foo-auth', 'foo_auth']
}));
I use it myself for other scenarios (need it in my remote methods): https://github.com/ShoppinPal/warehouse/blob/master/server/server.js#L17, but if that doesn't "just work" meaning if that doesn't directly translate into the value also being set into the soap-connector automagically ...
Then perhaps you can use a middleware to take the value and set into the loopback context, to be later picked up by your soap connector? Here's some (crude) middleware code of mine: https://github.com/ShoppinPal/warehouse/blob/master/server/server.js#L18-L35
... but I wonder where you might write code for the soap-connector to pick that value out of the loopback context? Because right now the instantiation looks to be global and one time so I wonder when you get a chance again to edit it.

Setting a cookie using JavaFX's WebEngine/WebView

I cannot seem to find any way to set a cookie programatically using WebEngine / WebView in JavaFX. The API doesn't give any idea as to how to obtain an HttpRequest-like object to modify the headers (which is what I use in the app for XML-RPC), or any sort of cookie manager.
No questions on this page seem to touch on the issue either - there is this but it just disables cookies when in applet to fix a bug, my app is on desktop btw.
The only way I image I could do it is by requesting the first page (which requires a cookie with a sessionID to load properly), getting an "access denied"-style message, executing some javascript in the page context which sets the cookie and then refreshing. This solution would be a horrible user experience though.
How do I set a cookie using WebEngine?
Update: Taking a clue from a question linked above, I tried digging around for some examples of using CookieManager and related APIs. I found this code, which I then tried to incorporate into my app, with weird results;
MyCookieStore cookie_store = new MyCookieStore();
CookieManager cookie_manager = new CookieManager(cookie_store, new MyCookiePolicy());
CookieHandler.setDefault(cookie_manager);
WebView wv = new WebView();
Now lets say we do this:
String url = "http://www.google.com/";
wv.getEngine.go(url);
Debugging in Eclipse after this request has been made shows that the cookie store map holds a cookie:
{http://www.google.com/=[NID=67=XWOQNK5VeRGEIEovNQhKsQZ5-laDaFXkzHci_uEI_UrFFkq_1d6kC-4Xg7SLSB8ZZVDjTUqJC_ot8vaVfX4ZllJ2SHEYaPnXmbq8NZVotgoQ372eU8NCIa_7X7uGl8GS, PREF=ID=6505d5000db18c8c:FF=0:TM=1358526181:LM=1358526181:S=Nzb5yzBzXiKPLk48]}
THAT IS AWESOME
WebEngine simply uses the underlying registered cookie engine! But wait, is it really? Lets try adding a cookie, prior to making the request...
cookie_store.add(new URL(url).toURI(), new HttpCookie("testCookieKey", "testCookieValue"));
Then I look at the request in Wireshark...
GET / HTTP/1.1
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/535.14 (KHTML, like Gecko) JavaFX/2.2 Safari/535.14
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cache-Control: no-cache
Pragma: no-cache
Host: www.google.com
Connection: keep-alive
No cookie for me :(
What am I doing wrong?
I have managed to solve this issue with the help of Vasiliy Baranov from Oracle. Vasiliy wrote to me:
Try putting the cookie into java.net.CookieHandler.getDefault() after
the WebView is instantiated for the first time and before the call to
WebEngine.load, e.g. as follows:
WebView webView = new WebView();
URI uri = URI.create("http://mysite.com");
Map<String, List<String>> headers = new LinkedHashMap<String, List<String>>();
headers.put("Set-Cookie", Arrays.asList("name=value"));
java.net.CookieHandler.getDefault().put(uri, headers);
webView.getEngine().load("http://mysite.com");
This will place the cookie into the store permanently, it should be sent out on every subsequent request (presumably provided that the server doesn't unset it).
Vasiliy also explained that WebView will install it's own implementation of the CookieHandler, while retaining cookies put into the default one.
Lastly, he mentions something quite intriguing:
Do not waste your time trying to use java.net.CookieManager, and
java.net.CookieStore. They are likely to cause problems with many
sites because they implement the wrong standard.
I tried googling after this but it doesn't seem to be common knowledge. If anyone is able to provide more details I would be grateful. It seems weird, since it seems CookieStore and CookieManager are used by a lot of software out there.
Solution for java.net.CookieManager
Cookies serialization:
List<HttpCookie> httpCookies = cookieManager.getCookieStore().getCookies();
Gson gson = new GsonBuilder().create();
String jsonCookie = gson.toJson(httpCookies);
Cookies deserialization:
Gson gson = new GsonBuilder().create();
List<HttpCookie> httpCookies = new ArrayList<>();
Type type = new TypeToken<List<HttpCookie>>() {}.getType();
httpCookies = gson.fromJson(json, type); // convert json string to list
for (HttpCookie cookie : httpCookies) {
cookieManager.getCookieStore().add(URI.create(cookie.getDomain()), cookie);
}

Getting "WSE003: The input was not a valid SOAP message" on every call to an WSE 2.0 SoapHttpRouter

I already tried some different SOAP-messages, even one which has an empty header and body, but without success to get into my SoapHttpRouter-derived class :-(
Also, when I hit the .asmx-URL with the browser it comes to that error.. here detailed stack trace of the error:
[NotSupportedException: WSE003: The input was not a valid SOAP message.]
Microsoft.Web.Services2.Messaging.SoapHttpRouter.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object asyncState) +134
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8677954
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
I hope that someone is out there who had the same problem. I would appreciate your help very much!
Typically when I get that message it's because there is a server side error and it's sending the default HTML error page back instead of the properly formatted SOAP message.
I would try stepping through the server-side code (if possible) to make sure there aren't any problems.
Were you aware that WSE 2.0 is extremely obsolete? Even more so than WSE 3.0.
I recently ran into this issue. The solution for me was to add the SOAPAction HttpHeader to the request, so that the request header looked something like this:
POST <web service url> HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: <action url>
Host: <host>
Content-Length: xxx