I'm using the library isomorphic-unfetch (https://www.npmjs.com/package/isomorphic-unfetch) to get JSON data from a Rest API. This is how I make the request:
const res = await fetch(
`url`
);
To access the body I simply need to do
const response = await res.json()
But how do I access the response headers? If I log the response to my server's console this is what I see:
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]: {
// stuff
},
[Symbol(Response internals)]: {
url: 'request url',
status: 200,
statusText: 'OK',
headers: Headers { [Symbol(map)]: [Object: null prototype] },
counter: 0
}
}
What's Symbol(Response internals)? And how do I access its headers property?
To access its headers use one of the following:
const res = await fetch(url);
console.log(res.headers.get('content-type');
// or
res.headers.forEach(header => console.log(header));
https://github.github.io/fetch/#Headers
When you run into a situation like this, you'll have access to those properties on the response object, so if you want to get access to the url property you'll simply have to write response.url and you'll get what you need.
fetch({someURL}, {
method: "POST"
}).then((response) => response).then((result) => {return result.url});
Related
I have this error in the console:
react_devtools_backend.js:4012 A non-serializable value was detected in an action, in the path: `meta.arg.config.adapter`. Value: ƒ xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var requestData = config.data;
var requestHeaders = config.headers;
var responseType = config.resp…
Take a look at the logic that dispatched this action:
{type: '[GET] dataGrid/runTask/rejected', payload: undefined, meta: {…}, error: {…}}
error
:
{name: 'Error', message: 'Request failed with status code 400', stack: 'Error: Request failed with status code 400\n at …tp://localhost:3000/static/js/bundle.js:208909:7)'}
meta
:
{arg: {…}, requestId: 'XNHo_e78g2enuXNwLe_pQ', rejectedWithValue: false, requestStatus: 'rejected', aborted: false, …}
payload
:
undefined
type
:
"[GET] dataGrid/runTask/rejected"
[[Prototype]]
:
Object
can anyone tell me where is the problem because the backend works well.
and the part of code that is mentioned is:
const requestConfig = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
};
export const getReportsList = createAsyncThunk(
'\[GET\], dataGrid/reportsList',
async (\_) = \ > {
const response = await getData(ENDPOINTS.all_reports)
return response.data
}
)
I found out that the problem is related to the headers.
I call 2 times the headers so in headers I had the another one!
simply after that the error solved.
You could Modify Your Code like this.
const requestConfig = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
export const getReportsList = createAsyncThunk(
'[GET], dataGrid/reportsList',
async (_, {getData, ENDPOINTS}) => {
const response = await getData(ENDPOINTS.all_reports, requestConfig)
return response.data
}
)
Note : The getData function and ENDPOINTS object need to be imported and provided to the createAsyncThunk middleware as dependencies in order to use them within the thunk.
I am working on user authentication using web tokens in react. I am using fetch() to make a POST request to my backend using CORS. Trying to use setToken() hook inside the .then() gives an error. I tried storing the token to another variable, and using setToken() outside the promise, but to no avail. Here's the code:
const [ token, setToken ] = useState('')
// Configuration for POST fetch method
const url = 'http://localhost:8080/users/login'
const requestOptions = {
method: 'POST',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify(userData)
}
let tempToken = ''
fetch(url, requestOptions)
.then(res => res.json())
.then(data => {
tempToken = data.token
// console.log(tempToken) // DEBUG
})
.catch(e => console.log(e))
setToken(tempToken)
// console.log(token) // This logs default value of token, which is ''
This is all inside a function. What is going wrong here? Also is there another way to do this, much appreciated. Thanks.
What is my problem: Cannot extract token from promise.
P.S: Also, on a completely different note, I tried using async await but it gave a response (shown below), where I couldn't even find the body of the json. Hence using .then()
Response {type: "cors", url: "http://localhost:8080/users/login", redirected: false, status: 200, ok: true, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "http://localhost:8080/users/login"
__proto__: Response
Fetch returns a promise, you need wait to get the token and then use setToken. Moreover you're calling fetch directly and updating the state even before rendering, that might leads to warnings/side effects. You can use useEffect hook to call api and update the state
useEffect(() => {
const url = 'http://localhost:8080/users/login'
const requestOptions = {
method: 'POST',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify(userData)
}
fetch(url, requestOptions)
.then(res => res.json())
.then(data => {
setToken(data.token)
})
.catch(e => console.log(e))
}, [])
I am trying to loop through 10 league of legends matches and for each match, call another api to get the match details. So far I have a function set up like this:
function getAllMatchData(ids) {
const promises = [];
_.take(ids, 1).forEach(id => {
const promise = fetch(`https://na1.api.riotgames.com/lol/match/v4/matches/${id}`, {
headers: {"X-Riot-Token": token}})
promises.push(promise);
})
return Promise.all(promises);
}
Since the api returns 100 matches, I only take the top 10 and then create an array of promises with them. I then do this to get the results:
getAllMatchData(_.map(data['matches'], 'gameId')).then(results => {
console.log(results);
}).catch(error => {
console.log(error);
})
But the console log for the results don't have any json data in it. It prints an array of objects that look like this:
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]: { body: [Gunzip], disturbed: false, error: null },
[Symbol(Response internals)]: {
url: 'https://na1.api.riotgames.com/lol/match/v4/matches/3556728982',
status: 200,
statusText: 'OK',
headers: [Headers],
counter: 0
}
}
I am not sure where the JSON data response is.
With fetch, you need to parse the response with the type of response you received.
const promise = fetch(`https://na1.api.riotgames.com/lol/match/v4/matches/${id}`, {
headers: {"X-Riot-Token": token}}).then(res => res.json())
In your case it's json. So it's as simple as calling res.json().
I am trying to write a basic graphql query with fetch that works when using apollo client. But it does not work with node-fetch.
The type definitions look like this:
type Query {
findLeadStat(print: PrintInput!): LeadStatWithPrint
}
input PrintInput {
printa: String!
service: String
}
type LeadStatWithPrint {
answered: Int!
printa: String!
service: String
}
This is the node-fetch query:
const fetch = require('node-fetch');
( async () => {
const uri = `http://localhost:3000/graphql/v1`;
const query = `
query findLeadStat(print: PrintInput!) {
findLeadStat(print: $print){
answered
printa
service
}
}
`;
// I also tried add a query: key inside data object
const data = {
print: {
printa: "62f69234a7901e3659bf67ea2f1a758d",
service: "abc"
}
}
const response = await fetch(uri, {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({query, data})
});
console.log('and the resp: ', response);
})()
It gives me:
url: 'http://localhost:3000/graphql/v1',
status: 400,
statusText: 'Bad Request',
It works in Apollo GraphQL Client. Why doesn't it work with fetch?
So when I was using async await with node-fetch, the response was pretty much useless. It was just telling me there was a 400 bad request error and then give me this long object of properties, none of them containing the actual error message.
But when I changed the fetch call to this:
const response = await fetch(uri, {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query, variables}) // same as query: query, variables: variables
})
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('ERROR: ', err));
There two lines right here:
.then(res => res.json())
.then(json => console.log(json))
made it clear what the issue was:
{
errors: [
{
message: 'Syntax Error: Expected $, found Name "fingeprint"',
locations: [Array],
extensions: [Object]
}
]
}
It appears node-fetch has two async events occurring and so await had to be used twice:
const response = await fetch(uri, {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query, variables}) // same as query: query, variables: variables
})
console.log('and the resp: ', await response.json());
A 400 status indicates your query was invalid or malformed. When this happens, the response will include a JSON body with an errors array that can be inspected to determine what exactly went wrong.
In this particular case, the issue is that your query includes a non-nullable variable ($print) but this variable was not provided along with the query.
When making a GraphQL request, the request body should be a JSON object with a query property and two other optional properties -- variables and operationName. operationName is used to identify which operation to execute if multiple operations were included in the provided document (the query property). Any non-nullable variables defined in the executed operation must be included as properties under the variables property, which is also an object. Nullable properties may be omitted altogether.
In other words, you need to change the data property in your request to variables in order for the server to recognize that the variable was provided with the request.
I am trying to use an API with HTTP POST request and It seems to work but when I get the response it's empty.
The API should receive base64 encoded image inside the body.
The argument imageToRead coming from a promise returned with the Camera component from react-native-camera. I'm not sure maybe the problem there?
This is the content:
imageToRead = "/var/mobile/Containers/Data/Application/01B81FC9-B171-11GB-9B48-9D06F89B175A/Documents/3A997ACD-D63C-41BD-9041-FDB834A0672A.jpg"
This API can also receive formData files and that how I tested it with and it went great in Node environment. But because my application is a native iOS application, I had to use other tools (like React Native) and can not use the same ones.
Code to test the API in Node:
var formData = {image: fs.createReadStream('/Users/Desktop/APITest/img/testOCR8.jpg')};
request.post({
url:'${url}',
formData: formData},
(err, httpResponse, body) => {
if (err) {
return console.error('upload failed:', err);
}
console.log(body);
});
You can see I use fs.createReadStream from the fs module to create stream of the file and then use it inside the request body.
I couldn't replicate the same thing using React Native (if you have a solution so I could do it with React Native it would be even better!!)
So I tried deferent way and tried to encode the file I got from the camera.capture() method that come with react-native-camera to base64 and to place it inside the body but the response I got is empty without any errors, just an empty object.
Code with React Native:
recognise = (imageToRead) => {
RNFetchBlob.fs.readFile(imageToRead , 'base64')
.then((data) => {
fetch('${url}',{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: data // the body contain the encoded image
})
.then((res) => { // promise returned with the response from the API
console.log(`i am the base64Image: ${data}`)
console.log('i am response', res)
})
.catch((errInFetch) => { // catch any error in the API
console.log('i am error:', errInFetch)
})
})
.catch((err) => {
console.log(err);
})
}
Response:
{ type: 'default',
status: 200,
ok: true,
statusText: undefined,
headers:
{ map:
{ server: [ 'nginx/1.10.3' ],
'content-type': [ 'application/json; charset="utf-8"' ],
'access-control-allow-origin': [ '*' ],
date: [ 'Thu, 10 May 2018 10:17:48 GMT' ],
'access-control-allow-headers': [ 'x-requested-with' ],
'content-encoding': [ 'gzip' ],
'content-length': [ '237' ],
connection: [ 'keep-alive' ] } },
url: 'https://api.openalpr.com/v2/recognize_bytes?secret_key=key&country=eu',
_bodyInit:
{ _data:
{ size: 371,
blobId: '5080ACA4-5D13-469C-B755-96B06A161FC6',
type: 'application/json',
offset: 0,
name: 'recognize_bytes' } },
_bodyBlob:
{ _data:
{ size: 371,
blobId: '5080ACA4-5D13-469C-B755-96B06A161FC6',
type: 'application/json',
offset: 0,
name: 'recognize_bytes' } } }
I hope someone can help with this. I have struggle with it for so long time.
fetch returns a promise containing the response (a Response object). then you again need to parse that using response.json() which returns promise resolving JSON.
fetch(url, {
body: JSON.stringify(data),
cache: 'no-cache',
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST', // *GET, POST, PUT, DELETE, etc.
})
.then(response => response.json())
for more info : read
.then((res) => {
console.log(`i am the base64Image: ${data}`)
console.log('i am response', res)
return res.json();
})
.then(res => {
console.log(res);
})
.catch((errInFetch) => { // catch any error in the API
console.log('i am error:', errInFetch)
})
Fetch response body returns a Promise that will be resolved by json().
So you can get your real data from res.json().
The 200 status is for a success get http request. Your API should return status 201 for post with a message instead of 200, for example:
res.status(201).send(data);
full example
also, you can look at the status 201 description