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
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.
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?
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);
});
}
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'])}
);
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