React API Fetch fail - javascript

I am trying to create a site where I will consume a web-api and display "users" on the site. I have an API-key that I have to put in the header as "x-api-key".
This is my code at the moment:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
items: []
}
}
componentDidMount() {
const myHeaders = new Headers();
myHeaders.append('x-api-key', 'KEY_HERE');
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
myHeaders.append('cache-control', 'no-cache')
fetch('URL_HERE', {
method: 'GET',
headers: myHeaders,
async: true,
})
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
render() {
var{isLoaded, items} = this.state;
if(!isLoaded) {
return <div>Loading...</div>;
}
else{
return (
<div className="App">
<ul>
{items.map(item => (
<li key={item.id}>
Name: {item.name} | Id:{item.id}
</li>
))};
</ul>
</div>
);
}
}
}
export default App;
The problem is I get these error messages in the console:
Failed to load http://URL/users: Response for preflight does not have
HTTP ok status.
Uncaught (in promise) TypeError: Failed to fetch
When I tried making a GET call in Postman I succeeded. So I suppose the problem is that the api-key doesnt get implemented in the header properly.
Appreciate the help, please let me know if there is anything else you need to know!

You need to remove below line from your code and after that, you need to handle OPTIONS method from server-side.
myHeaders.append('cache-control', 'no-cache')
You are getting this error because you are adding a header with 'x-api-key'. you have made the request complex. This requires the browser to make a preflight OPTIONS request to ask for permission to send the complex request.
The server you are making the request to is responding saying that OPTIONS requests are not allowed to that URL
You will need to modify the server and handle OPTION method properly so that it responds appropriately to the preflight CORS request.
You are not getting this error in postman because Postman doesn't need to make a preflight request.

Try to use axios if you want to fetch data using api.
It can be used at client side and server side as well and very much easy as well.
Here is the GitHub repo for your guide.
https://github.com/axios/axios

Related

Using SpreadShirt REST API with JavaScript / Fetch

What i try to do
I have a small ReactJS application. In this application, i try to do an REST request to the API of SpreadShirt via the JS Fetch API.
What fails
Basically i get no data. The console of the browser shows the following output:
Access to fetch at 'https://api.spreadshirt.net/api/v1/shops/100749149/sellables?mediaType=json' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
My Code
getData() {
const header = new Headers({
"Authorization": "SprdAuth apiKey=\"XXXXXXXXX"",
"User-Agent": "MukoSoft/1.0 (https://mydomain.de; my#mail.de)"
});
const options = {
method: 'GET',
headers: header
};
fetch('https://api.spreadshirt.net/api/v1/shops/100749149/sellables?mediaType=json', options)
.then(response => response.json())
.then(data => this.setState({ data: data }))
.then(() => this.setState({ loading: false }))
}
Does anyone has a hint for me, while i can't fetch via JavaScript? And can somebody explain, why the request via Postman works, but not via fetch API?
Since this is my first question on stack overflow, you can give me advices on how to formulate questions better

React CORS with URL Param despite setting CORS policy on

So I am trying to make a fetch request to get data before component loads using componentWillMount, but it keeps throwing error
Access to fetch at 'http://localhost:5000/mine/1/user_list' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Now I did try all solution proposed in other related question. Some of the things that I tried was setting 'Allow-CORS' param in the header. Also I have Google chrome tool that turns the CORS on and it is already on. Apart from that I also have tried keeping parameter in the fetch request with the mode.
But it is not working. Interesting thing is that if I try with constant URL (for example, http://locahost:5000/maintenance/company/fetch) the request goes through fine without any issue. However, when I use custom path URL as shown below (http://localhost:5000 + "mine/" + activeSite + "/user_list";) then issue starts. I have attached small snippet of the code for your reference.
My backend is in Python3 flask-restplus. It doesn't receive the request on backend. Error is thrown before even it makes fetch request. My controller has no such policy on for CORS on backend. But I assume if other request works fine in the app this should work fine without having that policy in the backend. Also I tested function with Swagger-UI and it works fine.
import React, { Component } from "react";
import Select from "react-select";
import { serverConst } from "../constants/system";
import { getAuthHeader } from "../helper/authHeader";
class TaskForm extends Component {
constructor(props) {
super(props);
this.state = {
assigned: "",
assigner: [],
reporter_list: [],
operationSucceed: false,
error: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentWillMount() {
let activeSite = localStorage.getItem("activeMinesite");
if (activeSite) {
const request_url = serverConst.SERVER_URL + "mine/" + activeSite + "/user_list";
fetch(request_url, {
method: "GET",
mode: "cors",
headers: getAuthHeader()
}).then(response => {
response.json().then(json => {
console.log(response);
});
});
}
}

axios put not happening throwing forbidden

I am new to axios.
I am trying to do an update to my api through put request. But I am getting the below error.
OPTIONS http://t/Sports/1 403 (Forbidden)
I am researched so many sites for axios but still I am not able to fix the issue
can you tell me how to fix it.
providing my code snippet below
<div className={classes.SportsEditTabContentFooter}>
<div>Sports Status</div>
<div>
<Button variant="outlined" className={classes.button}>
Cancel
</Button>
<Button variant="outlined" onClick={this.saveSports} className={classes.button}>
Save Sports test
</Button>
</div>
</div>
saveSports = () => {
console.log("saveSports---->");
console.log(this.state.Sports);
let saveSports = this.state.Sports;
saveSports.updatedBy = 'raj';
saveSports.priceRuleDescription = "test description";
axios
.put(
'http://t/Sports/' + saveSports.SportsID,
saveSports,
{ headers: { 'Content-Type': 'application/json' } }
)
.then(r => console.log(r))
.catch(e => console.log(e));
//this.toggleDrawer("right", false);
this.setState({ right: false });
this.setState({ snackBarOpen: true });
setTimeout(() => {
this.setState({ snackBarOpen: false });
}, 6000)
};
Since you try communicating different domain because of CORS browser automatically sends OPTIONS request. And backend does not expect this so it returns 403 for whatever reason.
Having this in mind your need
either change your client code to make request simple
place your client code to be run on the same domain where backend runs
run CORS proxy server as the same domain where client code is hosted - since OPTIONS aka preflight request is sent just by browser your code in, say, Node, does not require that
update target backend code to handle preflight OPTIONS request correctly
Each variant is enough to solve your issue. But it's up to you to decide what is more convenient in your case
PS just in case: no, there is no way to avoid preflight OPTIONS request to be sent by configuring axios, replacing axios with different package, fetch() call or native XmlHttpRequest or any other easy change in your client code since it's fundamental (security!) feature of modern web browsers

Getting tweets with React

I'm using the Twit package to pull tweets. I keep getting error 400, and
Failed to load https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterdev&count=10: 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:3000' is therefore not allowed access. The response had HTTP status code 400. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
The bulk of this was able to work with vanillajs, but once I imported into React, I've gotten these errors. How do I fix this? I've taken out the API keys for security.
import React, { Component } from 'react';
import Twit from 'twit';
export default class Twitter extends Component {
componentDidMount() {
const T = new Twit({
consumer_key: '...',
consumer_secret: '...',
access_token: '...',
access_token_secret: '...'
})
let params = {
screen_name: 'twitterdev',
count: 10
};
function getData(err, data, response) {
let tweet = data;
for (var i = 0; i<tweet.length; i++) {
console.log(tweet[i].text);
console.log();
}
}
T.get('statuses/user_timeline', params, getData);
}
render() {
return(
<div></div>
)
}
}
The Twitter API does not support CORS requests. That's what you are trying to do. Accessing API from a different domain. You'll have to create a bespoke url at your local server that proxies the request to the Twitter
API.

Reactjs with fetch for auth and access token, not able to parse response

I am pretty new to ReactJS.
I am using Chrome browser.
I am trying to create the sign in page using ReactJS. The page is simple with user id and password. Authentication happens on our SSO server, means I have to post data on the server using fetch call and get access_token as a response.
The problem is as below:
I am not getting response in the console. However, when I look at the Network tab on developer tools, I can see that there is a valid response with all required field including access_token in it.
Now sure how should I parse this.
Is this because fetch is async call?
Here is my entire page code.
P.S: some of the code is not getting formatted.
import React, {Component} from 'react';
import '../App/App.css';
import {FormGroup, FormControl, InputGroup} from 'react-bootstrap';
class Auth extends Component {
constructor(props) {
super(props);
this.state = {
userid: '',
password: '',
accessToken: ''
}
}
submit() {
console.log('state', this.state);
const BASE_URL = 'MY SSO URL';
const params = {
'grant_type': 'password',
'username': this.state.userid,
'password': this.state.password,
'client_secret': 'secred',
'client_id': 'client_id',
};
const formData = new FormData();
for (let p in params) {
formData.append(p, params[p]);
}
const headers = {
'Access-Control-Allow-Origin': '*'
};
const request = {
method: 'POST',
headers: headers,
body: formData,
mode: 'no-cors'
};
fetch(BASE_URL, request)
.then((response) => response.text())
.then((responseText) => {
console.log('text',responseText);
})
.catch((error) => {
console.warn(error);
});
console.log('all done');
}
render() {
return (
<div className="login">
<div className="legend">Signin</div>
<FormGroup>
<InputGroup>
<div className="input">
<FormControl
type="text"
placeholder="Enter User Id or email"
onChange={event => this.setState({userid: event.target.value})}
onKeyPress={
event => {
if (event.key === 'Enter') {
this.submit()
}
}}
/>
</div>
<div className="input">
<FormControl
type="password"
placeholder="enter password"
onChange={event => {
console.log(event.target.value)
this.setState({password: event.target.value})
}}
onKeyPress={
event => {
if (event.key === 'Enter') {
this.submit()
}
}}
/>
</div>
<FormControl
type="submit"
onClick={() => this.submit()}
/>
</InputGroup>
</FormGroup>
</div>
)
}
}
export default Auth;
I tried response.json() this gives error as: Unexpected end of input.
As far are your frontend JavaScript code for the fetch(…) request:
mode: 'no-cors'
Remove that. That’s the exact reason your code can’t access the response.
You never, ever want to do mode: "no-cors". The only thing that actually does is to tell the browser, Never let my frontend JavaScript code access the response from this request.
const headers = {
'Access-Control-Allow-Origin': '*'
};
Remove those lines too. Access-Control-Allow-Origin is a response header. You never want to send it in a request. The only effect that’ll have is to trigger a browser to do a preflight.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
I’m guessing that the reason you’re trying mode: 'no-cors' and sending Access-Control-Allow-Origin in the request is that you earlier tried the request without those and you got an error message in the browser console saying that the response lacked Access-Control-Allow-Origin.
If so, there’s no way you can get around that by making changes to your frontend JavaScript code—except by changing your code to instead make the request through a proxy, as outlined in the answer at "No 'Access-Control-Allow-Origin' header is present on the requested resource".
Either that or you need to get the owner of the server at your BASE_URL address to configure the server to send the Access-Control-Allow-Origin in its responses.
Here’s a longer explanation:
Your browser will only let your frontend JavaScript code access responses from cross-origin requests when the servers you’re making the requests to explicitly indicate they’re opting in to receiving cross-origin requests, which they do by sending the Access-Control-Allow-Origin response header in their responses.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS has more details.
Browsers are the only clients that enforce restrictions on cross-origin requests, and they only enforce them on web applications.
That’s why even when you see a No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin … is therefore not allowed access message in your devtools console, you’ll still be able to go to the Network tab in devtools and view the response there.
That’s because the server has sent the response and the browser has received it, but the browser is just refusing to allow your frontend JavaScript code to access the response due to the fact the server sending the response hasn‘t opted into to cross-origin requests by sending the Access-Control-Allow-Origin response header.
The reason you can get the response just fine when you make the request from curl, etc., is that no client other than browsers will refuse to allow your code to access the response if it lacks the Access-Control-Allow-Origin response header. But browsers always will.
And note that in none of this is the server doing any blocking or refusing to respond to any requests. The server always continues to just receive requests and send responses. The only difference is in whether the server sends the Access-Control-Allow-Origin header in the response, or not.

Categories

Resources