How do I POST JSON in Angular 2? - rest

I don't understand what I am doing wrong, my server returns "undefined" when I try to get the json.
POST(url, data) {
var headers = new Headers(), authtoken = localStorage.getItem('authtoken');
headers.append("Content-Type", 'application/json');
if (authtoken) {
headers.append("Authorization", 'Token ' + authtoken)
}
headers.append("Accept", 'application/json');
var requestoptions = new RequestOptions({
method: RequestMethod.Post,
url: this.apiURL + url,
headers: headers,
body: data
})
return this.http.request(new Request(requestoptions))
.map((res: Response) => {
if (res) {
return { status: res.status, json: res.json() }
}
});
}
And my function:
login(username, password) {
this.POST('login/', {test: 'test'}).subscribe(data => {
console.log(data)
})
}
When I try this, the request body looks like this:
So instead of sending actual json, it just sends "[object Object]".
Instead of "Request payload" it should be "JSON". What am I doing wrong?

I have been looking for a visual answer to the question of posting json data in Angular for a while, to no avail. Now that I eventually have something working, let's share:
Inlined
Let's assume you expect a json response body of type T.
const options = {headers: {'Content-Type': 'application/json'}};
this.http.post<T>(url, JSON.stringify(data), options).subscribe(
(t: T) => console.info(JSON.stringify(t))
);
Official doc
Extendable class
import { HttpClient, HttpHeaders } from '#angular/common/http';
export class MyHttpService {
constructor(protected http: HttpClient) {}
headers = new HttpHeaders({
'Content-Type': 'application/json'
});
postJson<T>(url: string, data: any): Observable<T> {
return this.http.post<T>(
url,
JSON.stringify(data),
{headers: this.headers}
)
}
The gist
In the beginning I missed this sort of 'nested' way to pass in the content-type:
{headers:{'Content-Type': 'application/json'}}

You need to stringify the payload
var requestoptions = new RequestOptions({
method: RequestMethod.Post,
url: this.apiURL + url,
headers: headers,
body: JSON.stringify(data)
})

The header should be
'Content-Type': 'application/json'
and
body: data
should be
body: JSON.stringify(data);

Related

How to write test case for Action.jsx class

Need to write testcase for below action.jsx class.How to write test case having headers.
export function getDeliveryDetail() {
return (dispatch, getState) => {
let createModalDescription = "";
let token = getState().auth.token;
let deliverOrderId = getState().reprocess.deliveryOrderId;
if (deliverOrderId) {
const headers = {
headers: {
"Content-type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${token}`
},
correspondenceAxios()
.get("/delivery-orders/" + deliverOrderId, headers)
.then(deliveryResponse => {
dispatch({
type: ACTION_TYPES.DELIVERY_ORDER_DETAIL,
payload: JSON.stringify(deliveryResponse.data, null, " ")
});
})
Need to write testcase for above action.jsx class.

axios POST using blob as responseType

So I am trying to download a file via axios and blob. The problem is I need to pass a password, and for that reason I can't use a "GET" request. For test purposes I still made a "GET" request to get me started. Since the project comes to an end I wanted to finally fix that issue but I can't find a solution.
That is my working code with a "GET" request to give you an idea.
axios({
url: `/api/download/?uuid=${uuid}&password=${password}`,
method: "GET",
responseType: "blob",
})
.then((response) => {
var fileURL = window.URL.createObjectURL(
new Blob([response.data])
);
var fileLink = document.createElement("a");
fileLink.href = fileURL;
fileLink.setAttribute("download", filename);
document.body.appendChild(fileLink);
fileLink.click();
self.showLottie = false;
})
.catch(function (error) {
self.showLottie = false;
alert("Download failed");
});
Ok, so basically all I had to do was putting the uuid and password in a params object.
axios({
url: `/api/download`,
method: "GET",
responseType: "blob",
params: {
uuid,
password,
},
})
.then((response) => {
var fileURL = window.URL.createObjectURL(
new Blob([response.data])
);
var fileLink = document.createElement("a");
fileLink.href = fileURL;
fileLink.setAttribute("download", filename);
document.body.appendChild(fileLink);
fileLink.click();
self.showLottie = false;
})
.catch(function () {
self.showLottie = false;
alert("Download failed");
});
Explanation: Are HTTPS URLs encrypted?

Angular 2 Http Post with Promise failing, not sending data

I am attempting to make a http.post call with angular 2. I have tested the call in postman, so I know that the api is working. I get an error, input empty which means that it isn't getting the data. I've read a few answers and articles, but not able to make a successful call with the data.
Can anyone give me some insight into what I am missing?
public upload(name: string, data: any, result, contentType: string) : Promise<Response> {
let headers = new Headers({ 'Content-Type': contentType });
let options = new RequestOptions({ headers: headers });
return this.http
.post(this.urlAPI, data, options)
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}
extractData(res:Response) {
console.log('res: ', res);
let body = res.json();
return Promise.resolve(res);
}
handleError(err: any): Promise<any> {
console.error('An Error has occured: ', err);
return Promise.reject(err);
}
I am not sure what is the type of your 'data'. Data has to be stringified before sent. Below is a workable version for me.
saveNote(note: ApprovalNoteModel): Observable<ApprovalNoteModel> {
let body = JSON.stringify(note);
let headers = this.utilsSvc.getAuthHeaders();
headers.set('Content-Type', 'application/json');
return this.http.post('cloud/api/approval/note', body,
{ headers: headers }
).map(response => response.json());
}
If it is a file, then you can not do that thru 'http', I believe. Here is my workable version.
addFileRequest(referenceId: number, licenseId: number, url: string, files: File[]): Observable<any> {
return Observable.create(observer => {
this.progressObserver = observer;
let formData: FormData = new FormData(),
xhr: XMLHttpRequest = new XMLHttpRequest();
formData.append('referenceId', referenceId);
formData.append('licenseId', licenseId);
for (let i = 0; i < files.length; i++) {
formData.append("uploads[]", files[i], files[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
observer.next(xhr.response);
observer.complete();
} else {
if (xhr.response.status)
observer.error(xhr.response);
else
observer.error({ 'status': xhr.status, '_body': xhr.response });
}
}
};
xhr.upload.onprogress = (event) => {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
};
xhr.open('POST', url, true);
xhr.setRequestHeader('Authorization', this.utilsSvc.getToken());
xhr.send(formData);
});
}

Angular 2 http post is returning 200 but no response is returned

My http call is returning 200 but no response is captured. My code inside subscribe is not being hit. The API is returning data when I test in postman. Here is my code.
getToken(authcode: string) {
var data = 'client_id=InspectWebApp_client&code=' + authcode + '&redirect_uri=http://localhost:3000&grant_type=authorization_code';
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers });
this.http.post('https://fedloginqa.test.com/as/token.oauth2', data, options)
.subscribe((res: Response) => {
var resultsToken = res.json();
localStorage.setItem("access_token",resultsToken.access_token)
//return this.inspections;
})
}
I was also facing the same problem. The problem was solved using the map function on Observables. Here is my implementation:
login(Username:string, Password:string) : Observable<Response>{
let headers = new Headers();
headers.append("Authorization", "Basic " + btoa(Username + ":" + Password));
headers.append("Content-Type", "application/x-www-form-urlencoded");
return this._http.post(this._baseUrl+"auth/login", " " , {headers: headers} )
.map((response: Response) => {
return response;
}).catch(this.handleError);
}
Here the handleError is a function to catch the excceptions generated. This is a function in login.service.ts that sends the username and password to the api to get data. You can see that I am returning response from the map function in this service. Now, this returned response can be caught in subscribe function in following way:
this._loginService.login(this.username, this.password)
.subscribe(
(response) => {
//Here you can map the response to a type.
this.apiResult = <IUser>response.json();
},
(err) => {
//Here you can catch the error
},
() => {this.router.navigate(['home'])}
);

Angular 2 - Dynamically find base url to use in the http requests (services)

I'm wondering if there is a dynamic way of getting the base url, to use in the http requests?
Is there any way of getting the http://192.123.24.2:8080 dynamically?
public getAllTickets() {
this._http.get('http://192.123.24.2:8080/services/', {
method: 'GET',
headers: new Headers([
'Accept', 'application/json',
'Content-Type', 'application/json'
])
})
So, I my request would look something like:
public getAvailableVersions() {
this._http.get('../services', {
method: 'GET',
headers: new Headers([
'Accept', 'application/json',
'Content-Type', 'application/json'
])
})
I'm looking for a way to not having to hard code the URL for the REST calls. Or is the only option to have a global variable with the URL?
Thanks!
You can create a file with your credentials
credentials.ts
export var credentials = {
client_id: 1234,
client_secret: 'secret',
host: 'http://192.123.24.2:8080'
}
And import it into your file
import {credentials} from 'credentials'
public getAllTickets() {
this._http.get(credentials.host + '/services/', {
method: 'GET',
headers: new Headers([
'Accept', 'application/json',
'Content-Type', 'application/json'
])
})
And with that you can handle dev/prod credentials
With version 2.0.0-beta.6 of Angular2, you can override the merge method
import {BaseRequestOptions, RequestOptions, RequestOptionsArgs} from 'angular2/http';
export class CustomRequestOptions extends BaseRequestOptions {
merge(options?:RequestOptionsArgs):RequestOptions {
options.url = 'http://192.123.24.2:8080' + options.url;
return super.merge(options);
}
}
You can register this class this way:
bootstrap(AppComponent, [HTTP_PROVIDERS,
provide(BaseRequestOptions, { useClass: CustomRequestOptions })
]);
Another approach could be to extend the HTTP object to add at the beginning of the request URL a base URL.
First you could create a class that extends the Http one with a baseUrl property:
#Injectable()
export class CustomHttp extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
super(backend, defaultOptions);
this.baseUrl = 'http://192.123.24.2:8080';
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
console.log('request...');
return super.request(this.baseUrl + url, options).catch(res => {
// do something
});
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
console.log('get...');
return super.get(this.baseUrl + url, options).catch(res => {
// do something
});
}
}
and register it as described below:
bootstrap(AppComponent, [HTTP_PROVIDERS,
new Provider(Http, {
useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new CustomHttp(backend, defaultOptions),
deps: [XHRBackend, RequestOptions]
})
]);
you can get your application context root as below
this.baseURL = document.getElementsByTagName('base')[0].href;
import {LocationStrategy} from 'angular2/router';
constructor(private locationStrategy:LocationStrategy) {
console.log(locationStrategy.prepareExternalUrl('xxx'));
}
See also https://github.com/angular/angular/blob/1bec4f6c6135d7aaccec7492d70c36e1ceeaeefa/modules/angular2/test/router/path_location_strategy_spec.ts#L88