Documentation from Express response.send allows for objects to be sent in the body, which I am sending as follows:
DBM.saveArticle(obj).then((val) => {
console.log(val); // verified here
res.send(val);
res.end();
// ... clip here
However on the client I am not getting the object. This is a Create in CRUD, and I am using fetch POST as follows to implement this.
// ... snip
const options = {
headers: {'Content-Type': 'application/json'},
method: 'POST',
body: JSON.stringify(this.state)
};
fetch("/articles/add", options)
.then((response) => {
console.log('DEBUG: Article Added: ', response); // nothing found here in response
this.props.dispatch({type: 'addArticle', component_state: state});
})
.catch((error) => {
console.log('fetch/POST error', error);
});
// ... snip
console.log from above looks like this, here is a pic, it is empty, as far as I can tell.
The response object is big, and I tried to click all about it, but it is possible I might have missed something.
The official docs for JavaScript fetch response object is here on MDN.
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Response_objects
This is just an HTTP response, not the actual JSON. To extract the JSON body content from the response, we use the json() method (defined on the Body mixin, which is implemented by both the Request and Response objects.)
https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
The Fetch API offers a concrete instance of a ReadableStream through
the body property of a Response object.
fetch returns the body as a ReadableStream to convert it to a JSON use response.json()
fetch('https://example.com/profile', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json()) // << this will convert the response to JSON object
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
The data in the ReadableStream is not accessible without consuming the stream, it's stored in a lower-level I/O source, called the underlying source, and there are two types of underlying source: push and pull sources.
In case of HTTP request it's a push source in the form of a TCP socket, where data is constantly being pushed from the OS level, and the data will be accessible to the consumer (your code) once you acquire a lock and start reading it, which is exactly what json() method do for you.
refer to this for more details https://streams.spec.whatwg.org/#rs-model
Related
I have a React application where I am changing POST method to GET with the request body as it is. It works fine with POST request however when I change the method to GET, it gives me error-
message: "org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public
My Front End Code-
export const setData = (getData) => dispatch => {
axios({
method: 'GET',
url: 'http://localhost:8080/api',
headers: {
'Content-Type': 'application/json'
},
data: getData
})
.then (response => {
dispatch({
type: API_DATA,
payload: response.data
})
dispatch({
type: SET_SEARCH_LOADER,
payload: false
})
})
.catch(function(error) {
})
}
Can someone let me know what I am missing here. As per my understanding, http allows to have a request body for GET method.
As per my understanding, http allows to have a request body for GET method.
While this is technically true (although it may be more accurate to say that it just doesn't explicitly disallow it), it's a very odd thing to do, and most systems do not expect GET requests to have bodies.
Consequently, plenty of libraries will not handle this.
The documentation for Axois says:
// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
Under the hood, if you run Axios client side in a web browser, it will use XMLHttpRequest. If you look at the specification for that it says:
client . send([body = null])
Initiates the request. The body argument provides the request body, if any, and is ignored if the request method is GET or HEAD.
If you want to send parameters with get request in axios, you should send parameters as params.
If you want to set "Content-type":"application/json" and send params with get request, you should also send an empty data object.
For example:
const AUTH_TOKEN = 'Bearer token'
const config = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': AUTH_TOKEN,
},
data: {},
params: {
"post_id": 1
}
}
axios.get("http://localhost/api/v1/posts/", config)
This is not axios, the error origniates from the java backend you're talking to. The public field in your request body is missing.
If you just want to send the data as parameters (which would be odd), pass it using params instead of data (as shown here: https://github.com/axios/axios#example).
I personally don't think your API should support GET with a request body (talk to the devs and ask for documentation).
I might be overlooking the obvious but is there a way to get the fetch request? (not the response).
A normal fetch looks like something this:
fetch(url, {
method: method,
headers: new Headers({
'Authorization': token,
'Content-Type': 'application/json'
}),
body: payload
})
.then((response) => response.json())
.then((responseData) => {
console.log(responseData);
})
I want the ability to get the method, headers, body, and are data that are passed to fetch in a variable that can be passed around to other methods like a log.
You can't get the request information from a Response object (the thing the promise from fetch is fulfilled with), but you can build a Request object yourself, pass it around, and then use that with fetch. The Request constructor accepts the same parameters fetch does, but instead of doing the operation, it just returns the Request object for it.
For instance, here's your code done that way:
// Building the request, which you can then pass around
const request = new Request(url, {
method: method,
headers: new Headers({
"Authorization": token,
"Content-Type": "application/json"
}),
body: payload
});
// Using it
fetch(request)
.then((response) => {
if (!response.ok) { // Don't forget this part!
throw new Error(`HTTP error ${response.status}`);
}
return response.json();
})
.then((responseData) => {
console.log(responseData);
});
(Aside: Note the slight addition to the first fulfillment handler above, to handle the fetch API footgun. fetch doesn't reject its promise on HTTP errors, only network errors; you have to check for HTTP errors yourself. More in my blog post here.)
I have a React application where I am changing POST method to GET with the request body as it is. It works fine with POST request however when I change the method to GET, it gives me error-
message: "org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public
My Front End Code-
export const setData = (getData) => dispatch => {
axios({
method: 'GET',
url: 'http://localhost:8080/api',
headers: {
'Content-Type': 'application/json'
},
data: getData
})
.then (response => {
dispatch({
type: API_DATA,
payload: response.data
})
dispatch({
type: SET_SEARCH_LOADER,
payload: false
})
})
.catch(function(error) {
})
}
Can someone let me know what I am missing here. As per my understanding, http allows to have a request body for GET method.
As per my understanding, http allows to have a request body for GET method.
While this is technically true (although it may be more accurate to say that it just doesn't explicitly disallow it), it's a very odd thing to do, and most systems do not expect GET requests to have bodies.
Consequently, plenty of libraries will not handle this.
The documentation for Axois says:
// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
Under the hood, if you run Axios client side in a web browser, it will use XMLHttpRequest. If you look at the specification for that it says:
client . send([body = null])
Initiates the request. The body argument provides the request body, if any, and is ignored if the request method is GET or HEAD.
If you want to send parameters with get request in axios, you should send parameters as params.
If you want to set "Content-type":"application/json" and send params with get request, you should also send an empty data object.
For example:
const AUTH_TOKEN = 'Bearer token'
const config = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': AUTH_TOKEN,
},
data: {},
params: {
"post_id": 1
}
}
axios.get("http://localhost/api/v1/posts/", config)
This is not axios, the error origniates from the java backend you're talking to. The public field in your request body is missing.
If you just want to send the data as parameters (which would be odd), pass it using params instead of data (as shown here: https://github.com/axios/axios#example).
I personally don't think your API should support GET with a request body (talk to the devs and ask for documentation).
I am posting request to my backend server using fetch api in React js
const formData = new FormData();
formData.append("image", file);
formData.append("userId", currentUser.id);
formData.append("sliderNumber", sliderNumber);
const myHeaders = new Headers();
myHeaders.append("Content-Type", file.type);
myHeaders.append("Aceess-Control-Allow-Origin", "*");
fetch("http://localhost:4000/upload/slide-image", {
method: "POST",
headers: myHeaders,
mode: "no-cors",
body: formData
})
.then(response => response)
.then(data => console.log("Printing data: ", data));
};
In elixir backend
def upload(conn, params) do
# uploading code
#send response to the client with amazon s3 image url
send_resp(conn, 200, image_url)
end
but Response object from fetch api is empty
Response {
body: null
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
}
And it doesn't change when I respond with status code 400.
It seems like fetch api is not building Reponse object correctly in some point. Because I can find correct status code and response body in browser network tab. But Response object doesn't hold response from backend server.
Any idea?
If you are expecting a text response from your server, then on your first .then(.. you should do like:
fetch("http://localhost:4000/upload/slide-image", {
method: "POST",
headers: myHeaders,
mode: "no-cors",
body: formData
})
.then(response => response.text()) // <---
.then(data => console.log("Printing data: ", data));
fetch returns a Promise that resolves to a Response. When you use .text() at this stage, what you actually do is to take the Response stream, read it to completion and return a promise that will resolve with a text.
Aside from that, you also use mode: "no-cors" (as other users mentioned on their answers) that limits you in many ways. For example, even if you follow my instructions above, you will get an empty string, even if you are trying to return something from your server. And that will be because of this mode.
You can find more details about it here, under bullet no-cors.
Your Content-Type is wrong. When sending files along with other data, the Content-Type should still be multipart/form-data.
mode: "no-cors",
You set the mode to no-cors, so the response is Opaque, which means you can't see inside it.
Don't do that if you need to read the response.
Asides:
myHeaders.append("Content-Type", file.type);
That's the wrong content-type for a form data object. Don't set the content-type. The fetch API will set the correct one automatically.
myHeaders.append("Aceess-Control-Allow-Origin", "*");
Access-Control-Allow-Origin, which you misspelt, is a response header, not a request header.
.then(response => response)
Returning the response unchanged is rather pointless. You probably want response.text() if you are getting a plain URL back.
The accepted answer solved my pinpoint.
if you are expecting a JSON object from the backend, use
.then((response) => response.json())
I am using fetch to get the API response for GET and POST requests. When an error occurs, I am able to see the status code and the text i.e, 400 Bad Request. However, there is additional information being passed that explains why the error was thrown (i.e. username did not match). I can see this additional message in the response payload via Firefox developer tool's console but I am not sure how to get it via handling the fetch response.
Here's an example request:
fetch(url, {
method: 'POST',
body: JSON.stringify({
name: name,
description: description
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + token
}
}).then(response => {
if (!response.ok) {
throw Error(response.statusText)
}
return response
})
.catch(error => {
console.log(error)
})
Any ideas? Thanks.
Thank you everyone for your suggestions.
This tutorial helped me understand what to do.
https://css-tricks.com/using-fetch/
My problem was that when there is an error, the response is not JSON, it's text. So I needed to do something like this (taken from css-tricks.com):
fetch('https://api.github.com/users/chriscoyier/repos')
.then(response => response.text())
.then(data => {
console.log(data)
});
You seem to be passing only the statusText field of the response, which corresponds to the HTTP status code (And not the response body) - for example Bad Request for HTTP response code 400.
You can read the response body using one of the methods defined on the Response object returned by the fetch API. For example, if you're expecting a JSON response body, you can have:
const onSuccess = response => {
// Do something with the response
// What you return from here will go to the next .then
}
const onFailure = response => {
// response.json() returns a promise that resolves to the JSON sent in the body
// Note that whatever is returned from here will go to the next .then
// To go to the next .catch, you can throw from here
return response.json().then(jsonResponse => console.log(jsonResponse))
}
fetch(url, {
method: 'POST',
body: JSON.stringify({
name: name,
description: description
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + token
}
}).then(response => {
if (!response.ok) {
throw response
}
return response
})
.then(onSuccess, onFailure)
.catch(err => { /* Any error thrown from the handlers will be caught here */ })
You can have a look at the Response object documentation for more details.
Based off the docs, I'd do something more along the lines of this:
const response = await fetch('http://example.com/movies.json')
const myJson = await response.json();
console.log(JSON.stringify(myJson));
Otherwise you have to do everything inside of your .then().
In regards to the additional text you are looking for, that's totally dependent on the response object, and I have no way of knowing without seeing it.
#Voxum, your answer is missing important info, like a method..and ; await is good, but remember it should be in an async function, and you dont need to use it if you "thenify" .then() as that returns the promise. from the Fetch docs, that is their basic get/HTML example. i think the OP is asking for a API call for different types of methods, which will require a more advanced setup.
The thing is with a 400 response, the server is not giving you a response message as the 404 (for example) is telling you the page is not found. Usually the only time a server will give you a response message is when you get a good (success/200). there will usually be a message at response.json() or response.text() depending on your data coming back.
after you call fetch with the url, method and any headers use
.then((response) => {console.log(response.json());}); for json and use
.then((response) => {console.log(response.text());}); for xml/text
OP has the fetch set up properly but just needs to use response.json() or response.text(). again, a 200 response can still be a "incorrect password" and this is where you'll use this. don't expect a response body on the 400/500s. good luck!