While implementing the V3 API I face the following CORS problem with my Ionic2/Angular2 application:
XMLHttpRequest cannot load https://api.yelp.com/v3/businesses/search. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access. The response had HTTP status code 404.
While using the V2 of the API, I was "bypassing" the CORS problem using http.jsonp whish isn't applicable anymore, because the authorization bearer should be added in the header of the GET request (as far as I understood, a Jsonp header can't be modified).
That's why I tried
private queryYelp(yelpOAuth:YelpCommunication.YelpOAuthSignature, nextTo:AddressLocation.Location):Promise<{}> {
let params:URLSearchParams = new URLSearchParams();
params.set('limit', '' + Resources.Constants.Default.YELP.LIMIT);
params.set('latitude', '' + nextTo.coordinates[0]);
params.set('longitude', '' + nextTo.coordinates[1]);
params.set('radius', '' + Resources.Constants.Default.YELP.RADIUS);
params.set('sort_by', Resources.Constants.Default.YELP.SORT.BEST_MATCHED);
let headers:Headers = new Headers();
headers.append('Authorization', 'Bearer ' + yelpOAuth.access_token);
let options:RequestOptions = new RequestOptions({
headers: headers,
search: params,
withCredentials: true
});
return new Promise((resolve, reject) => {
this.http.get(Resources.Constants.Default.YELP.URL, options)
.map(res => res.json())
.subscribe((businesses:Yelp.YelpBusiness[]) => {
resolve(businesses);
}, (errorResponse:Response) => {
reject(errorResponse);
});
});
}
or
private queryYelp(yelpOAuth:YelpCommunication.YelpOAuthSignature, nextTo:AddressLocation.Location):Promise<{}> {
return new Promise((resolve, reject) => {
let xhr:XMLHttpRequest = new XMLHttpRequest();
let formData:FormData = new FormData();
formData.append('limit', '' + Resources.Constants.Default.YELP.LIMIT);
formData.append('latitude', '' + nextTo.coordinates[0]);
formData.append('longitude', '' + nextTo.coordinates[1]);
formData.append('radius', '' + Resources.Constants.Default.YELP.RADIUS);
formData.append('sort_by', Resources.Constants.Default.YELP.SORT.BEST_MATCHED);
xhr.onload = () => {
console.log("status " + xhr.status);
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status == 201) {
let businesses:Yelp.YelpBusiness[] = JSON.parse(xhr.responseText);
resolve(businesses);
} else {
reject();
}
};
xhr.onerror = () => {
alert('Woops, there was an error making the request.');
};
xhr.open("GET", Resources.Constants.Default.YELP.URL, true);
xhr.setRequestHeader("Authorization", 'Bearer ' + yelpOAuth.access_token);
xhr.send(formData);
});
}
and both solution weren't successful aka both solution leaded to the CORS error listed above.
Did I miss something or how could I query the Yelp API v3 from Ionic2 / Angular2?
Thx Best regards
P.S.: Note that my OAuth access_token isn't exposed. The authentication is generated by my backend.
UPDATE
After @Thierry Templier answer I found a solution which works for Ionic2.
When debugging in the browser, I query the Yelp API V3 using a proxy. Therefor I add in ionic.config.json file
"proxies": [{
"path": "/yelp/v3/businesses",
"proxyUrl": "https://api.yelp.com/v3/businesses"
}]
and do the query like following
this.http.get('http://localhost:8100/yelp/v3/businesses/' + 'search', ...
note that following would also work
this.http.get('/yelp/v3/businesses' + 'search', ...
When running in iOS and Android, the proxy should not be use aka not gonna work. Therefor I do the query like following in my service
this.http.get('https://api.yelp.com/v3/businesses/search, ...
Of course, to have something handy, I write a gulp task which allow me to switch between environments.
But, this solution is only applicable for Ionic2. If I would have to implement it in Angular2 in a website, I would need I guess a proxy too, not sure about it. Therefor I opened a copy of that task in the issues list of the Yelp API V3