How to send Http Form with parameters by ktor-client - kotlin

I've found nearly everywhere in ktor-client documentation and examples they use empty formData to show how the client works
formParameters: Parameters = Parameters.Empty
So what's the kotlin/ktor way to fill it with parameters?

Ktor uses this approach to fill the parameters:
client.submitForm<HttpResponse>(
url = "https://foo.com/login",
formParameters = Parameters.build {
append("_username", username)
append("_password", password)
})

Alternatively, you can also simply pass the form data using formData, e.g.:
client.post<HttpResponse>("https://example.com/login") {
formData {
parameter("username", username)
parameter("password", password)
}
}

I've found at least three ways to post www-urlencoded form:
return httpClient.submitForm("url") {
parameter("key", "value")
}
return httpClient.post("url") {
FormDataContent(Parameters.build {
parameter("key", "value")
})
}
return httpClient.post("url") {
formData {
parameter("key", "value")
}
}
append() method is marked as internal and not working with ktor 1.6.4

client.get{
url("https://api.yelp.com/v3/businesses/search")
contentType(ContentType.Application.Json)
headers {
append(HttpHeaders.Authorization, "Bearer $API_KEY")
}
formData {
parameter("location","NYC") //use this wey
}
}

Related

Web API 2 Dictionary binding from JSON

This seems like a duplicate, but I've tried every permutation of the other answers I can come up with, and WebAPI always fails to bind a parameter of type Dictionary<string, string>. The parameter values is never populated. It usually is instantiated as an empty dictionary, though some variation I tried (lost track which) it was just null. Have tried various data shapes (see javascript snip), and both GET and POST verbs, changing the parameter attribute between [FromUri] and [FromBody] as appropriate.
Controller Method
[Route("api/reports/generate/{reportid}")]
[HttpPost]
public object GenerateReport(Guid reportid, [FromBody] Dictionary<string, string> values) {
// logic snipped...
}
Angular Service (though I have tried the same requests from Postman)
runReport(reportid: string, values: any) {
const keys = Object.keys(values);
// shape: { "values": { "someKey": "some string value", "anotherKey": "value" } }
const params: any = { values: values};
// shape: {"values": [{key: "someKey", value: "some string value"}, ...]}
// params.values = keys.map(k => ({ key: k, value: values[k] }));
// shape: { "values[0].Key": "someKey", "values[0].Value": "some string value", ...}
// keys.forEach((k, i) => {
// params[`values[${i}].Key`] = k;
// params[`values[${i}].Value`] = values[k];
// });
// try as get request (with parameter as [FromUri])
// return this._http.get(`/api/reports/generate/${reportid}`, {
// params, responseType: 'blob'
// });
// try as POST request (with parameter as [FromBody])
return this._http.post(`/api/reports/generate/${reportid}`, params, { responseType: 'blob' });
}
Quite late, but try this -
[Route("api/reports/generate/{reportid}")]
[HttpPost]
public object GenerateReport(Guid reportid) {
var values = this.Url.Request.GetQueryNameValuePairs(); //This would return the values in Key-Value dictionary format.
}

send URL parameters to Express with Angular 2

I'm using this Angular service to get data from Express:
getRestaurants(districtId) : Observable<void[]>{
let params: URLSearchParams = new URLSearchParams();
params.set('id', districtId);
return this.http.get(this.url, { search: params })
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
I was using this URL http://localhost:5050/api/district/restaurants?id=8
It works fine if in Express I use req.query But I need to use this new URL http://localhost:5050/api/district/:id/restaurants and use req.params in Express.
My problem is that I can't set the :id parameter using Angular without modifying the URL string and I suppose that there is a better way to do this task. Thanks for your help
What about this:
private url = 'http://localhost:5050/api/district/:id/restaurants';
private _prepareUrl(districtId: number): string {
return this.url.replace(':id', districtId);
}
getRestaurants(districtId) {
// ...
this.http.get(this._prepareUrl(districtId), ...);
// ...
}
You could use the Router's function createUrlTree, but you will have a prepare-function too..
private urlPrefix = 'http://localhost:5050/api';
constructor(private _router: Router) { }
private _prepareUrl(districtId: number): string {
return this.urlPrefix + this._router.createUrlTree(['district', districtId, 'restaurants']).toString();
}
getRestaurants(districtId) {
// ...
this.http.get(this._prepareUrl(districtId), ...);
// ...
}

PDF Blob is not showing content, Angular 2

I have problem very similar to this PDF Blob - Pop up window not showing content, but I am using Angular 2. The response on question was to set responseType to arrayBuffer, but it not works in Angular 2, the error is the reponseType does not exist in type RequestOptionsArgs. I also tried to extend it by BrowserXhr, but still not work (https://github.com/angular/http/issues/83).
My code is:
createPDF(customerServiceId: string) {
console.log("Sending GET on " + this.getPDFUrl + "/" + customerServiceId);
this._http.get(this.getPDFUrl + '/' + customerServiceId).subscribe(
(data) => {
this.handleResponse(data);
});
}
And the handleResponse method:
handleResponse(data: any) {
console.log("[Receipt service] GET PDF byte array " + JSON.stringify(data));
var file = new Blob([data._body], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
I also tried to saveAs method from FileSaver.js, but it is the same problem, pdf opens, but the content is not displayed. Thanks
I had a lot of problems with downloading and showing content of PDF, I probably wasted a day or two to fix it, so I'll post working example of how to successfully download PDF or open it in new tab:
myService.ts
downloadPDF(): any {
return this._http.get(url, { responseType: ResponseContentType.Blob }).map(
(res) => {
return new Blob([res.blob()], { type: 'application/pdf' })
}
}
myComponent.ts
this.myService.downloadPDF().subscribe(
(res) => {
saveAs(res, "myPDF.pdf"); //if you want to save it - you need file-saver for this : https://www.npmjs.com/package/file-saver
var fileURL = URL.createObjectURL(res);
window.open(fileURL); / if you want to open it in new tab
}
);
NOTE
It is also worth mentioning that if you are extending Http class to add headers to all your requests or something like that, it can also create problems for downloading PDF because you will override RequestOptions, which is where we add responseType: ResponseContentType.Blob and this will get you The request body isn't either a blob or an array buffer error.
ANGULAR 5
I had the same problem which I lost few days on that.
Here my answer may help others, which helped to render pdf.
For me even though if i mention as responseType : 'arraybuffer', it was unable to take it.
For that you need to mention as responseType : 'arraybuffer' as 'json'.(Reference)
Working code
downloadPDF(): any {
return this._http.get(url, { responseType: 'blob' as 'json' }).subscribe((res) => {
var file = new Blob([res], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
}
Referred from the below link
https://github.com/angular/angular/issues/18586
Amit,
You can rename the filename by adding a variable to the end of the string
so saveAs(res, "myPDF.pdf");
Becomes
saveAs(res, "myPDF_"+someVariable+".pdf");
where someVariable might be a counter or my personal favorite a date time string.
This worked for me
var req = this.getPreviewPDFRequest(fd);
this.postData(environment.previewPDFRFR, req).then(res => {
res.blob().then(blob => {
console.clear();
console.log(req);
console.log(JSON.stringify(req));
const fileURL = URL.createObjectURL(blob);
window.open(fileURL, '', 'height=650,width=840');
})
});
Server side (Java/Jetty) : REST service that returns a File Response
The File Response itself will automatically be parsed into a pdf blob file by Jetty (because of the annotation #Produces("application/pdf") ), in other to be send to and read by the web client
#GET
#Path("/download-pdf/{id}")
#Produces("application/pdf")
public Response downloadPDF(#ApiParam(value = "Id of the report record")
#PathParam("id") Long id) {
ResponseBuilder response = null;
try {
PDFReportService service = new PDFReportService();
File reportFile = service.getPDFReportFile(id);
response = Response.ok((Object) reportFile);
response.header("Content-Disposition","attachment; filename="+reportFile.getName());
return response.build();
} catch (DomainException e) {
response = Response.serverError().entity("server.error");
}
return response.build();
}
Client side code (angular 2) : grab the blob and print it in a new browser tab
The key is to insure that you read the request reponse as a blob (as the server returned a blob; in my case)
Now, I tried so hard but I finally figured out that Angular 2 has not implemented any function to handle blob responses (neither res['_body'], nor res.blob() worked for me)
So I found no other workaround than using JQuery ajax to perform that file blob request, like following:
public downloadPDFFile() {
let fileURL = serverURL+"/download-pdf/"+id;
let userToken: string = your_token;
showWaitingLoader();
$.ajax({
url: fileURL,
cache: false,
headers: {
"Content-Type": "application/json",
"Authorization": "Basic " + userToken
},
xhrFields: {
responseType: 'blob' //Most important : configure the response type as a blob
},
success: function(blobFile) {
const url = window.URL.createObjectURL(blobFile);
window.open(url);
stopWaitingLoader();
},
error: function(e){
console.log("DOWNLOAD ERROR :", e);
}
});
}

Get data change with observer mutation?

I'm trying to get the changed value of a HTML-Node.
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.addedNodes[0].data == "9"){
dostuff();
}
}
}
But javascript returns only an object and no array of
addedNodes.mutation.addedNodes[0]
prints out:
<TextNode textContent="9">
Where can I get the value of the changed HTML-Node?
Thanks alot.
Ok, found a solution via Stackoverflow
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
[].call(mutation.addedNodes).forEach(function (addedNode) {
if(addedNode.textContent == "9"){
dostuff();
}
});
});
});

Migrating from YUI2 to YUI3 and domready

I want to migrate the javascript in my site from YU2 to YUI3, but I am only a poor amateur programer and I am stuck at the first pitfall.
I have the following code:
MyApp.Core = function() {
return {
init: function(e, MyAppConfig) {
if (MyAppConfig.tabpanels) {
MyApp.Core.prepareTabpanels(MyAppConfig.tabpanels);
}
},
prepareTabpanels: function(tabpanels) {
// Code here
}
}
}();
var MyAppConfig = {
"tabpanels":{"ids":["navigation"]}
};
YAHOO.util.Event.addListener(window, "load", MyApp.Core.init, MyAppConfig);
How can I pass the MyAppConfig object to the MyApp.Core.init function by using YUI3 "domready" event listener?
Thanks in advance!
You should be able to do something like:
var MyApp = {};
MyApp.Core = function(){ return {
init: function(MyAppConfig) {
console.log(MyAppConfig);
},
prepareTabpanels: function(tabpanels) {
// Code here
}
}
}();
var MyAppConfig = {
"tabpanels":{"ids":["navigation"]}
};
YUI().use('node', 'event', function(Y){
Y.on('domready', MyApp.Core.init, this, MyAppConfig);
});
Note that the event is not passed in as the first parameter, it is the config.
Y.on accepts parameters as <event_type>, <callback_function>, <context>, <params>..
any parameter after the third item is passed through to the callback function so MyAppConfig becomes the first parameter in your init.
EDIT
See the YUI3 API documentation here: http://developer.yahoo.com/yui/3/api/YUI.html#method_on