Spring MVC with Reactjs fetch error - javascript

I am getting a similar error from (here)[Getting "TypeError: failed to fetch" when the request hasn't actually failed
My method is annotated with #CrossOrigin
With postman my request works fine ( from locally)
see POST to http://star-is.info:8080/app-1.0.0-BUILD-SNAPSHOT/register with headers Content-Type application/x-www-form-urlencoded and passing a string with firstname
Locally works fine but my form (here)[http://star-is.info:8082/] does not
const data = {};
data['firstname'] = this.state.firstname;
console.log('submitSignup');
fetch('http://localhost:8080/app-1.0.0-BUILD-SNAPSHOT/register', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then((response) => response.json()
.catch(err => {
console.err(`'${err}' happened!`);
return {};
})).then(function (body) {
console.log(body);
})
.catch(error => {
alert(error);
});
Now I am getting a reply from server
{firstname: null}
but why is firstname not being passed to the server..
The way i achieved this much as using register as endpoint to call in fetch
and using proxy in package.json
I removed JSON.stringify with the data and still it is null
See with postman I get the same string back
I even tried this
const data = {'firstname' : this.state.firstname};
it is still returned null

Finally it works. I had to encode the data being sent. Is there a better way to do this in Reactjs for more complex objects
const searchParams = Object.keys(data).map((key) => { return encodeURIComponent(key) + '=' + encodeURIComponent(data[key]); }).join('&');
And then use searchParams in the body of fetch

Related

Fetch: HTTP GET Showing data not working via web api consuming gRPC

I'm trying see in console some data from a http Get method but it doesn't work, showing me error 400 and Idk how I get is errors... I did with the post method and it works well
I'm also trying to do authentication with bearer tokens but idk if this is correct
This is the fetch get method:
function getUsers() {
fetch(uri_3_2, {
headers: {
'Accept': 'application/json',
'Content-type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem("key")}`,
}
//the localStorage.getItem("key") is a key I have when I first to other fetch call,
//so this getUsers() is calling after the first fetch I have
})
.then(response => response.json())
.then(data => _displayItems(data))
.catch(error => console.error('Unable to get Users.', error));
}
function _displayItems(data) {
console.log(data.Email); //undefined
console.log(data.Username); //undefined
console.log(data); //this works but don't show the data, I have so it gives me error...
}
I think this one is correct but I will show anyway
Controller method
[HttpGet("getAllUserInfo_2"), Authorize] //message is empty but it works
public async Task<ActionResult<ListUsersResponse>> GetAll_2(MessageRequest message)
{
var results = await _userClient.GetAllUsersAsync(message);
return Ok(results);
}
gRPC service
public override Task<ListUsersResponse> GetAllUsers(MessageRequest request, ServerCallContext context)
{
ListUsersResponse response = new ListUsersResponse();
var query = from emp in _context.Users_4
select new ListUserResponse()
{
Username = emp.Username,
Email = emp.Email
};
response.LstUsers.AddRange(query.ToArray());
return Task.FromResult(response);
}

Not getting data in fetch even if the status is 200 in react

I am having below problem with the fetch function:
React code:
componentDidMount() {
this.userService.getLoggedInUser()
.then(user => {
this.setState({user: user});
console.log(this.state.user);
})
}
This the course service file code:
getLoggedInUser(){
const USER_API_URL = API_URL + "/api/profile";
return fetch(USER_API_URL, {
headers : {
'Content-Type' : 'application/json'
},
method : "POST"
}).then(response => response.clone()).then(data => {
console.log(data);
return data;
}).catch(function (err) {
console.log(err)
});
}
I am just trying to get the logged in user from the server. While using postman to do the same, I am getting the output as expected.
Server Code:
#PostMapping("/api/loggedInUser")
public Faculty getLoggedInUser(HttpSession session){
return (Faculty)session.getAttribute("currentUser");
}
Class in the server is defined as:
#RestController
#CrossOrigin(origins = "http://localhost:3000", allowCredentials ="true")
public class UserService {
In postman, I am getting the below output:
{
"id": 100,
"username": "bird",
"password": "bird",
"firstName": "Alice",
"lastName": "Kathie"
}
But in the react app, I am getting in the console as:
Response {type: "cors", url: "http://localhost:8080/api/profile", redirected: false, status: 200, ok: true, …}
But there is no data body to return or parse. I am not sure what I am doing wrong here. I have tried changing the then method in the fetch to various types, like response.clone().json() etc, but, in most cases, I am getting the output as "promise rejected, unexpected end of json input".
How can I solve this problem?
Thanks
Looks like the error is in how you are handling your response:
}).then(response => response.clone()).then(data => {
The data in your second .then() isn't returning the fetch response, it is returning the details of the fetch itself. In .then(response => you probably want to do:
.then(response => {
return response.json()
}
It isn't clear what you are trying to do with response.clone(), as this typically creates a clone of the response for use with caching or something -- what are you trying to do with the clone?
If you're using it in a cache function maybe you could:
.then(response => {
someCacheFunction(response.clone())
return response.json()
}
or if you are setting it to a pre-defined variable for some use:
var responseClone;
... // code omitted
.then(response => {
responseClone = response.clone()
return response.json()
}
Found the answer. Main problem was with the cookies. While fetching, we need to make sure following is set:
getLoggedInUser = () => {
const USER_API_URL = API_URL + "/api/profile";
return fetch(USER_API_URL, {
headers : {
'Content-Type' : 'application/json'
},
method : "POST",
'credentials': 'include'
}).then(response => {
console.log(response);
return response.json()
}).catch(function (err) {
console.log(err)
});
}
"credentials":"include" is necessary so that the browser is accepting cookies and the same cookie is used to retrieve the data from the server.
I've found that fetch is unreliable. Try axios instead. See https://axios-http.com/docs/intro for info, or run npm i axios and add it to your project with import axios from 'axios', then call axios.get(YOUR_URL).
Probably too old a thread by now, but maybe this will help a little.

Axios - DELETE Request With Request Body and Headers?

I'm using Axios while programming in ReactJS and I pretend to send a DELETE request to my server.
To do so I need the headers:
headers: {
'Authorization': ...
}
and the body is composed of
var payload = {
"username": ..
}
I've been searching in the inter webs and only found that the DELETE method requires a "param" and accepts no "data".
I've been trying to send it like so:
axios.delete(URL, payload, header);
or even
axios.delete(URL, {params: payload}, header);
But nothing seems to work...
Can someone tell me if it's possible (I presume it is) to send a DELETE request with both headers and body and how to do so?
So after a number of tries, I found it working.
Please follow the order sequence it's very important else it won't work
axios.delete(URL, {
headers: {
Authorization: authorizationToken
},
data: {
source: source
}
});
axios.delete does supports both request body and headers.
It accepts two parameters: url and optional config. You can use config.data to set the request body and headers as follows:
axios.delete(url, { data: { foo: "bar" }, headers: { "Authorization": "***" } });
See here - https://github.com/axios/axios/issues/897
Here is a brief summary of the formats required to send various http verbs with axios:
GET: Two ways
First method
axios.get('/user?ID=12345')
.then(function (response) {
// Do something
})
Second method
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
// Do something
})
The two above are equivalent. Observe the params keyword in the second method.
POST and PATCH
axios.post('any-url', payload).then(
// payload is the body of the request
// Do something
)
axios.patch('any-url', payload).then(
// payload is the body of the request
// Do something
)
DELETE
axios.delete('url', { data: payload }).then(
// Observe the data keyword this time. Very important
// payload is the request body
// Do something
)
Key take aways
get requests optionally need a params key to properly set query parameters
delete requests with a body need it to be set under a data key
axios.delete is passed a url and an optional configuration.
axios.delete(url[, config])
The fields available to the configuration can include the headers.
This makes it so that the API call can be written as:
const headers = {
'Authorization': 'Bearer paperboy'
}
const data = {
foo: 'bar'
}
axios.delete('https://foo.svc/resource', {headers, data})
For those who tried everything above and still don't see the payload with the request - make sure you have:
"axios": "^0.21.1" (not 0.20.0)
Then, the above solutions work
axios.delete("URL", {
headers: {
Authorization: `Bearer ${token}`,
},
data: {
var1: "var1",
var2: "var2"
},
})
You can access the payload with
req.body.var1, req.body.var2
Here's the issue:
https://github.com/axios/axios/issues/3335
For Delete, you will need to do as per the following
axios.delete("/<your endpoint>", { data:<"payload object">})
It worked for me.
I had the same issue I solved it like that:
axios.delete(url, {data:{username:"user", password:"pass"}, headers:{Authorization: "token"}})
Actually, axios.delete supports a request body.
It accepts two parameters: a URL and an optional config. That is...
axios.delete(url: string, config?: AxiosRequestConfig | undefined)
You can do the following to set the response body for the delete request:
let config = {
headers: {
Authorization: authToken
},
data: { //! Take note of the `data` keyword. This is the request body.
key: value,
... //! more `key: value` pairs as desired.
}
}
axios.delete(url, config)
I hope this helps someone!
If we have:
myData = { field1: val1, field2: val2 }
We could transform the data (JSON) into a string then send it, as a parameter, toward the backend:
axios.delete("http://localhost:[YOUR PORT]/api/delete/" + JSON.stringify(myData),
{ headers: { 'authorization': localStorage.getItem('token') } }
)
In the server side, we get our object back:
app.delete("/api/delete/:dataFromFrontEnd", requireAuth, (req, res) => {
// we could get our object back:
const myData = JSON.parse(req.params.dataFromFrontEnd)
})
Note: the answer from "x4wiz" on Feb 14 at 15:49 is more accurate to the question than mine! My solution is without the "body" (it could be helpful in some situation...)
Update: my solution is NOT working when the object has the weight of 540 Bytes (15*UUIDv4) and more (please, check the documentation for the exact value). The solution of "x4wiz" (and many others above) is way better. So, why not delete my answer? Because, it works, but mostly, it brings me most of my Stackoverflow's reputation ;-)
i found a way that's works:
axios
.delete(URL, {
params: { id: 'IDDataBase'},
headers: {
token: 'TOKEN',
},
})
.then(function (response) {
})
.catch(function (error) {
console.log(error);
});
I hope this work for you too.
To send an HTTP DELETE with some headers via axios I've done this:
const deleteUrl = "http//foo.bar.baz";
const httpReqHeaders = {
'Authorization': token,
'Content-Type': 'application/json'
};
// check the structure here: https://github.com/axios/axios#request-config
const axiosConfigObject = {headers: httpReqHeaders};
axios.delete(deleteUrl, axiosConfigObject);
The axios syntax for different HTTP verbs (GET, POST, PUT, DELETE) is tricky because sometimes the 2nd parameter is supposed to be the HTTP body, some other times (when it might not be needed) you just pass the headers as the 2nd parameter.
However let's say you need to send an HTTP POST request without an HTTP body, then you need to pass undefined as the 2nd parameter.
Bare in mind that according to the definition of the configuration object (https://github.com/axios/axios#request-config) you can still pass an HTTP body in the HTTP call via the data field when calling axios.delete, however for the HTTP DELETE verb it will be ignored.
This confusion between the 2nd parameter being sometimes the HTTP body and some other time the whole config object for axios is due to how the HTTP rules have been implemented. Sometimes an HTTP body is not needed for an HTTP call to be considered valid.
For Axios DELETE Request, you need to include request payload and headers like this under one JSON object:
axios.delete(URL, {
headers: {
'Authorization': ...
},
data: {
"username": ...
}
})
Why can't I do it easily as I do similar to POST requests?
Looking at the Axios documentation, we see that the methods for .get, .post... have a different signature:
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
Notice how only post, patch and put have the data parameter. This is because these methods are the ones that usually include a body.
Looking at RFC7231, we see that a DELETE request is not expected to have a body; if you include a body, what it will mean is not defined in the spec, and servers are not expected to understand it.
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
(From the 5th paragraph here).
In this case, if you are also in control of the server, you could decide to accept this body in the request and give it whatever semantics you want. May be you are working with somebody else's server, and they expect this body.
Because DELETE requests with bodies are not defined in the specs, and because they're not common, Axios didn't include them in those method aliases. But, because they're possible, you can do it, just takes a bit more effort.
I'd argue that it would be more conventional to include the information on the url, so you'd do:
axios.delete(
`https://example.com/user/${encodeURIComponent(username}`,
{ headers: ... }
)
or, if you want to be able to delete the user using different criteria (sometimes by username, or by email, or by id...)
axios.delete(
`https://example.com/user?username=${encodeURIComponent(username)}`,
{ headers: ... }
)
Not realated to axios but might help people tackle the problem they are looking for. PHP doesn't parse post data when preforming a delete call. Axios delete can send body content with a request.
example:
//post example
let url = 'http://local.test/test/test.php';
let formData = new FormData();
formData.append('asdf', 'asdf');
formData.append('test', 'test');
axios({
url: url,
method: 'post',
data: formData,
}).then(function (response) {
console.log(response);
})
result: $_POST Array
(
[asdf] => asdf
[test] => test
)
// delete example
axios({
url: url,
method: 'delete',
data: formData,
}).then(function (response) {
console.log(response);
})
result: $_POST Array
(
)
to get post data on delete call in php use:
file_get_contents('php://input');
axios.post('/myentity/839', {
_method: 'DELETE'
})
.then( response => {
//handle success
})
.catch( error => {
//handle failure
});
Thanks to:
https://www.mikehealy.com.au/deleting-with-axios-and-laravel/
I encountered the same problem...
I solved it by creating a custom axios instance. and using that to make a authenticated delete request..
const token = localStorage.getItem('token');
const request = axios.create({
headers: {
Authorization: token
}
});
await request.delete('<your route>, { data: { <your data> }});
I tried all of the above which did not work for me. I ended up just going with PUT (inspiration found here) and just changed my server side logic to perform a delete on this url call. (django rest framework function override).
e.g.
.put(`http://127.0.0.1:8006/api/updatetoken/20`, bayst)
.then((response) => response.data)
.catch((error) => { throw error.response.data; });
Use {data: {key: value}} JSON object, the example code snippet is given below:
// Frontend Code
axios.delete(`URL`, {
data: {id: "abcd", info: "abcd"},
})
.then(res => {
console.log(res);
});
// Backend Code (express.js)
app.delete("URL", (req, res) => {
const id = req.body.id;
const info = req.body.info;
db.query("DELETE FROM abc_table WHERE id=? AND info=?;", [id, info],
(err, result) => {
if (err) console.log(err);
else res.send(result);
}
);
});
Axios DELETE request does supports similar what POST request does, but comes in different formats.
DELETE request payload sample code:
axios.delete(url, { data: { hello: "world" }, headers: { "Authorization": "Bearer_token_here" } });
POST request payload sample code:
axios.post(url, { hello: "world" }, { headers: { "Authorization": "Bearer_token_here" } });
Noticed that { hello: "world" } is configured in different ways, but both performs same functions.
this code is generated from post man and it's perfectly work for delete api request with body.
var data = JSON.stringify({"profile":"false","cover":"true"});
var config = {
method: 'delete',
url: 'https://api.fox.com/dev/user/image',
headers: {
'Authorization': 'Bearer token',
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});

Axios POST request fails with error status code 500: Internal Server error

I'm trying to send a POST request locally with a username and password in the body through Axios.
I'm deploying a Flask app on http://127.0.0.1:5000/login, which handles the /login route. The POST request fails with the following error
POST http://127.0.0.1:5000/login 500 (INTERNAL SERVER ERROR)
Error: Request failed with status code 500
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
I researched a bit and thought it might be a problem with CORS, but this doesn't seem to be the case because I tried an Axios GET request and it worked fine (response logged properly). Here's part of my code
axios.get("http://127.0.0.1:5000").then(function(response) {
console.log(response);
}).catch(function(error) {
console.log(error);
})
axios.post("http://127.0.0.1:5000/login", {
username: this.state.username,
password: this.state.password
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.log(error);
})
Looking at Chrome DevTools, I can see that the POST request payload is properly populated. I then tried printing out the keys server-side in the Flask app using the following code, but I got nothing, empty. (which was expected since the POST request failed)
dict = request.form
for key in dict:
print('form key '+dict[key])
HOWEVER using Postman with the corresponding keys and values works properly and returns a response and prints out the keys (see above). Where is the failure coming from? Why would the POST request fail when a GET seems to work just fine?
Feb 2021. Wasted 2 hours on this. Not much help on this famous library on internet.
Solution:
In the catch block, the error which will always be 500 internal server error
so, use error.response.data instead of error.
Code:
try {
let result = await axios.post( // any call like get
"http://localhost:3001/user", // your URL
{ // data if post, put
some: "data",
}
);
console.log(result.response.data);
} catch (error) {
console.error(error.response.data); // NOTE - use "error.response.data` (not "error")
}
Update:
I ended up writing a common function for handing error:
File: common.app.js
export const errorUtils = {
getError: (error) => {
let e = error;
if (error.response) {
e = error.response.data; // data, status, headers
if (error.response.data && error.response.data.error) {
e = error.response.data.error; // my app specific keys override
}
} else if (error.message) {
e = error.message;
} else {
e = "Unknown error occured";
}
return e;
},
};
More info: https://github.com/axios/axios#handling-errors
So I also got stuck in the same problem and the solution that I found was something like this :
let data = JSON.stringify({
username: this.state.username,
password: password
});
const response = axios.post(url,data,{headers:{"Content-Type" : "application/json"}});
This solution worked for me.
Apparently Axios didn't take kindly to the raw JSON object
{username: this.state.username, password: password}
but passing the data into a FormData object seemed to work just fine!
After working 2 hours, I realized I made a mistake about the body and data. So, in the axios make sure you pass the data like this.
async function loadToken(){
try{
response = await axios({
url: ``,
headers: {
'Authorization': '',
'Content-Type': '',
},
data: '',
method: 'POST'
});
let data = response.data;
return {
tokenInfo:data,
timestamp:new Date().getTime()
}
} catch(err) {
console.log("err->", err.response.data)
return res.status(500).send({ret_code: ReturnCodes.SOMETHING_WENT_WRONG});
}
}
My previous code pass the data like this, which is wrong
async function refreshToken(){
try{
let headers = {
authorization: '',
'Content-Type': ''
}
let url = ``
let body = {
grant_type: '',
refresh_token: global.tokenInfo.refresh_token
}
data = await axios.post(url, body, {headers});
let data = response.data
console.log(data)
return {
tokenInfo:data,
timestamp:new Date().getTime()
}
} catch(err) {
console.log("err->", err.response)
return res.status(500).send({ret_code: ReturnCodes.SOMETHING_WENT_WRONG});
}
}
Simply try my first code, hope that solves your issue.
Most of the time it happens because of using wrong content type header.
Open postman and see "Body" tab. There you can find the content type of your post data. It's also accessible from "Headers" tab. There should be a Content-Type header. The correct format of data you send through a POST request depends on Content-Type header. for example, json content type requires a json (javascript object) data or form-data content type requires a FormData.
To set a header in axios, change the code like this:
axios.post("http://127.0.0.1:5000/login", {
username: this.state.username,
password: this.state.password
}, {
headers: {'Content-Type': 'application/json'}
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.log(error);
})
I had similar error i had the JSON capital and it should have been lowercase

IHttpActionResult won't return JSON object

I'm trying to return a JSON result to my client using IHttpActionResult.
My .Net code, looks like this:
[AllowAnonymous, HttpPost, Route("")]
public IHttpActionResult Login(LoginRequest login)
{
if (login == null)
return BadRequest("No Data Provided");
var loginResponse = CheckUser(login.Username, login.Password);
if(loginResponse != null)
{
return Ok(new
{
message = "Login Success",
token = JwtManager.GenerateToken(login.Username, loginResponse.Roles),
success = true
});
}
return Ok( new
{
message = "Invalid Username/Password",
success = false
});
}
This doesn't work though, as I never seem to see the JSON on the response after my JavaScript fetch:
const fetchData = ( {method="GET", URL, data={}} ) => {
console.log("Calling FetchData with URL " + URL);
var header = {
'Content-Type': "application/json",
}
// If we have a bearer token, add it to the header.
if(typeof window.sessionStorage.accessToken != 'undefined')
{
header['Authorization'] = 'Bearer ' + window.sessionStorage.accessToken
}
var config = {
method: method,
headers: header
};
// I think this adds the data payload to the body, unless it's a get. Not sure what happens with a get.
if(method !== "GET") {
config = Object.assign({}, config, {body: JSON.stringify(data)});
}
// Use the browser api, fetch, to make the call.
return fetch(URL, config)
.then(response => {
console.log(response.body);
return response;
})
.catch(function (e) {
console.log("An error has occured while calling the API. " + e);
});
}
There is no JSON available in the body.
How do I get aresult back to my client to parse? response.body doesn't have the json object.
The console.log shows:
While the request/response shows:
Using striped's advice: console.log(response.json())
I see the message there. It seems to be in the wrong place. Shouldn't it be in the body?
Fetch works like this
Body methods
Each of the methods to access the response body returns a Promise that
will be resolved when the associated data type is ready.
text() - yields the response text as String
json() - yields the result of JSON.parse(responseText)
blob() - yields a Blob
arrayBuffer() - yields an ArrayBuffer
formData() - yields FormData that can be forwarded to another request
I think you need to
return fetch(URL, config)
.then(response => response.json())
.catch(e => console.log("An error has occured while calling the API. " + e));
doc here: https://github.github.io/fetch/
Your are making a GET request but your controller method is expecting a POST request.

Categories