When I make a post request the angular 2 http is not sending this request
this.http.post(this.adminUsersControllerRoute, JSON.stringify(user), this.getRequestOptions())
the http post is not sent to the server but if I make the request like this
this.http.post(this.adminUsersControllerRoute, JSON.stringify(user), this.getRequestOptions()).subscribe(r=>{});
Is this intended and if it is can someone explain me why ? Or it is a bug ?
Since the post method of the Http class returns an observable you need to subscribe it to execute its initialization processing. Observables are lazy.
You should have a look at this video for more details:
https://egghead.io/lessons/rxjs-rxjs-observables-vs-promises
You must subscribe to the returned observable if you want the call to execute.
See also the following angular documentation "Communicating with backend services using HTTP".
Starting the request
For all HttpClient methods, the method doesn't begin its HTTP request until you call subscribe() on the observable the method returns.
This is true for all HttpClient methods.
You should always unsubscribe from an observable when a component is destroyed.
All observables returned from HttpClient methods are cold by design.
Execution of the HTTP request is deferred, letting you extend the observable with additional operations such as tap and catchError before anything actually happens.
Calling subscribe() triggers execution of the observable and causes HttpClient to compose and send the HTTP request to the server.
Think of these observables as blueprints for actual HTTP requests.
In fact, each subscribe() initiates a separate, independent execution of the observable.
Subscribing twice results in two HTTP requests.
const req = http.get<Heroes>('/api/heroes');
// 0 requests made - .subscribe() not called.
req.subscribe();
// 1 request made.
req.subscribe();
// 2 requests made.
On a related note: The AsyncPipe subscribes (and unsubscribes) for you automatically.
Get method doesn't require to use the subscribe method but post method requires the subscribe. Get and post sample codes are below.
import { Component, OnInit } from '#angular/core'
import { Http, RequestOptions, Headers } from '#angular/http'
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/catch'
import { Post } from './model/post'
import { Observable } from "rxjs/Observable";
#Component({
templateUrl: './test.html',
selector: 'test'
})
export class NgFor implements OnInit {
posts: Observable<Post[]>
model: Post = new Post()
/**
*
*/
constructor(private http: Http) {
}
ngOnInit(){
this.list()
}
private list(){
this.posts = this.http.get("http://localhost:3000/posts").map((val, i) => <Post[]>val.json())
}
public addNewRecord(){
let bodyString = JSON.stringify(this.model); // Stringify payload
let headers = new Headers({ 'Content-Type': 'application/json' }); // ... Set content type to JSON
let options = new RequestOptions({ headers: headers }); // Create a request option
this.http.post("http://localhost:3000/posts", this.model, options) // ...using post request
.map(res => res.json()) // ...and calling .json() on the response to return data
.catch((error:any) => Observable.throw(error.json().error || 'Server error')) //...errors if
.subscribe();
}
}
Related
I want to achieve the same done here but in next.js.
Next.js provides methods to fetch data from a server and using them as props. I don't know whether you want to use it before rendering a page (like getServerSideProps) or when, for example, you click a button, but I suppose its the first case.
My personal preference when doing requests, is axios, so I will use it in this example:
export async function getServerSideProps({ req, res }) {
// Here is where we make the request
const result = await axios({
method: 'HEAD', // here is where we declare that we want to use the HEAD method
url: "your server url", // this is the url where we want to send the request
headers: {} // if you want to add custom headers, you can do it here
})
// Here we are logging the result of the request
console.log(result)
}
You can refer to the next.js documentation on data fetching and the axios documentation
Have a great day and I hope you succeed on your projects
In React Apollo client, we have some links configured.
const apollo = new ApolloClient({
cache: new InMemoryCache(),
link: from([
onErrorLink,
afterwareLink,
httpLink
])
});
In our application, when session times out we return the response with 200 status and some response headers (timeout: true). By using these response headers we need to show some dialog on UI. The response header also has content-type: text/html. Also remember, sessions are maintained on federal level (SSO) in our organization and we do not control response context for that.
When session times out and we receive response from server, Apollo react client onError link fires up and we try to access response as below.
const context = operation.getContext();
const response = context.response;
const headers = response.headers;
In above code, context never has response property and hence response is undefined. Due to this, I am not able to access header values.
Analysis
const afterwareLink = new ApolloLink((operation, forward) => {
return forward(operation).map(response => {
const context = operation.getContext();
const response = context.response;
const headers = response.headers;
return response;
})
};
I have seen in case of error, only onError is resolved and afterwareLink map function never triggers.
response is populated in context only if comes via forward function given by Apollo.
In successful API calls, afterwareLink map function do resolves and I am able to find all headers just fine.
Solutions online are similar but just does not work.
I am stumped here. I can clearly see response headers in Dev Tools and Fiddler. It's for sure there. Just Apollo is not allowing me to access that. In my case, networkError or graphQLErrors are not of much use.
This was few steps problem to solve. Sharing my findings and solutions below.
Headers
Make sure the response from API has the following header value.
Access-Control-Allow-Origin: http://uiclient.com
Access-Control-Expose-Headers: *
The first header will make sure the browser is satisfied and allows UI to resolve the response. The second header will make sure UI can read the response headers.
Response Content Type
In my case response type was not as expected by Graph and cannot be changed as this was from federal layer (SSO). Others can face the same problem in the case of third party service, 401, 403 or other status codes.
To resolve the problem, I wrote a simple custom fetch function and attached it to HttpLink.
const httpFetch = (uri, options) => {
return fetch(uri, options).then(response => {
// ... read headers from response.headers.
if (response.status >= 500) { // or handle 400 errors
return Promise.reject(response.status);
}
return response;
}).catch(error => {
return Promise.reject(error);
});
};
const httpLink = new HttpLink({
uri: 'https://serviceapi.com',
fetch: httpFetch
});
Handle httpFetch
This technique can be used to read data in Apollo client when your response is not JSON (or is JSON). In my case, I checked the header first and if the header had session timeout value then resolved the promise using a custom object (as the main content will be HTML).
The above steps will mostly help you to customize any response in Apollo. Also note, I did not write any custom middleware (or link) to address this issue.
I need to execute some code after every PUT, PATCH and POST. I don't want in every axios call to execute my code after I get the response; I want the code to be declared in one place to make sure its execution is triggered for every PUT/POST/PATCH. I thought of axios reponse interceptors but you get to do something before your return the reponse while as in my case, I want the response forst to be returned, then I will execute my code.
checkout for axios middleware
import axios from 'axios';
import { Service } from 'axios-middleware';
const service = new Service(axios);
service.register({
onRequest(config) {
console.log('onRequest');
//EDIT YOUR REQUEST CONFIG
return config;
},
onResponse(response) {
console.log('onResponse');
//EDIT YOUR RESPONSE
return response;
}
});
axios('https://jsonplaceholder.typicode.com/posts/1')
.then(({ data }) => console.log('Received:', data));
I'm in Angular 2 trying to connect to an API where eI do not have access server side.
I know this API and token are ok works As I converting an existing PHP app to Angular.
Here is myapp.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class DxdService {
private apiUrl = 'https://path/to/my/api/';
constructor(private _http: Http){
}
createAuthorizationHeader(headers: Headers) {
headers.append('X-Auth-Token','myvalidkey');
}
getValueFromApi(){
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this._http.get(this.apiUrl, headers)
.map(res => res.json());
}
}
This return invariably
GET https://path/to/my/api/ 401 (Unauthorized)
XMLHttpRequest cannot load https://path/to/my/api/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:3000' is therefore not allowed access. The response had HTTP status code 401.
What I can't figure out here is, did the way I set my headers x-auth-token is wrong, or did I fight agains the Access-Control-Allow-Origin CORS issue.
Considering I can't access server side to change Access-Control-Allow-Origin header response, if the way I set my headers is right, how can I keep developing locally?
You won't be able to fix this issue from a Frontend perspective, you need to access the server to make the proper adjustments and making it accesible from your Angular application
You can try implementing JSONP as the method in your request. Just keep in mind that JSONP only works with GET
$http({
method: 'JSONP',
url: url
}).
success(function(status) {
//your code when success
}).
error(function(status) {
//your code when fails
});
You can find more answers related to this issue here
In Angular 2 I am trying to control http request/response to set/read some headers when sending request and getting response.
I just override HttpRequest like this, and it is working for me :
#Injectable()
export class HttpRequest extends RequestOptions {
constructor() {
super({
method: RequestMethod.Get,
headers: new Headers({
'X-Some-Header': 'some-content'})
});
}
}
But for overriding Response I have problem :
#Injectable()
export class HttpResponse extends Response {
constructor(responseOptions: ResponseOptions) {
super(responseOptions);
console.log("RESPONSE IS CREATED!!!!!!!");
}
}
The constructor never being called and here it is the bootstrap:
bootstrap(AppComponent,
[ ROUTER_PROVIDERS
,HTTP_PROVIDERS
,provide(RequestOptions, {useClass: HttpRequest})
,provide(Response, {useClass: HttpResponse})
]);
The reason for overriding the response is to read some response headers and control for 404-Not Page Found globally and ....
Thanks,
You can't override Response I remember seeing that it is being created using new Response in one of the related Http classes instead of requesting it from the injector, which is reasonable because Response needs to be a dufferent instance for each request.
You could implement it in a few ways: create base service class or provide custom xhr implementation:
#Injectable()
export class CustomBrowserXhr extends BrowserXhr {
constructor() {}
build(): any {
let xhr:XMLHttpRequest = super.build();
/*...add headers, listeners etc...*/
return <any>(xhr);
}
}
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);