I have been trying to make a http PUT request for sending data to the server. Each time, when I try to send the request the data in the server becomes null. I have tested the server side code by sending correct format of data seems the server side is working fine. Going back to the client side code, I have noticed that during fetch operation the data in the response becomes in 'ReadableStream'. Don't know actually what does that mean. Can anybody help me finding out the mistakes if it is possible from the below information.
I am trying to send the data from the react component:
updateData(data)
the format of the data I am trying to send is an Object:
{first:"first", second:"second"}
And then in my api handler:
const updateData = async (data) => {
const resource = await getResource('PUT', {
data,
});
const url = `${process.env.updateAPI}/Update`;
return handleFetch(url, resource);
};
And then in my handleFetch function:
const handleFetch = async (url, resource) => {
const res = await fetch(url, resource);
if (!res.ok) {
throw new Error(`Request failed, status ${res.status}`);
}
const resData = await res.json();
return resData;
};
getResource function is accepting the parameters and returns the required methods, data and the header where 'Content-Type': 'application/json', is provided and handling the data like: body = JSON.stringify(data);
During debugging I have noticed that the res from fetchHandlers becomes like this:
I am actually confused, why in the body the data becomes 'ReadableStream' instead of the actual data I am trying to send or is this the problem I am having null values. Can anybody help me with that?, it will be highly appreciated. Thanks in Advance
If your data return type is not JSON or you don't want JSON then use text()
As an example:
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(function(response) {
return response.text();
}).then(function(data) {
console.log(data); // this will be a string
});
Related
my fetch is stuck in pending when I query a fastapi endpoint in local dev.
followed this blog and a few others - https://damaris-goebel.medium.com/promise-pending-60482132574d
Using this fetch code (having simplified it drastically just to get a simple solution working)
function fastapiRequest(path) {
return fetch(`${path}`)
.then((response) => {
return response;
}
);
into a constant variable i.e.,
const xxxx = fastapiRequest(
`http://0.0.0.0:8008/xcascasc/Dexaa/Emo.json?Magic=Dexxaa&emotion=expressions`
);
Ideally I want to use UseSWR to do this as I'm using next.js, but first of all, just need it to work :)
A postman query like this works fine to return a value
curl --location --request GET 'http://0.0.0.0:8008/xcaxc/dexxa/emo.json?analysis=statistical&substance=dexxa&emo=powa' \
--header 'x_token: 13wdxaxacxasdc1'
the value is left like this in console.log
data show here? Promise {<pending>}
With the initial response being
Response {type: 'cors', url: 'url', redirected: false, status: 200, ok: true, …}
Update based on answers.
Using each of the proposed answers, I am still not getting the data returned appropriately. i.e.,
function fastApiRequest(path) {
console.log("really begins here");
return fetch(`${path}`, { mode: 'cors' })
.then((response) => {
console.log('response', response);
return response.json();
})
.catch((err) => {
throw err;
});
}
async function test() {
console.log('begins');
return await fastApiRequest(
`http://0.0.0.0:8008/xxxx/dex/adea.json?deaed=adedea&adee=deaed&adeada=adeeda`
);
}
const ansa = test();
Is giving a response of pending at the moment.
The backend is built with fastapi, with these CORS, I'm wondering if I need to give it more time to get the data? (postman works fine :/)
def get_db():
try:
db = SessionLocal()
yield db
finally:
db.close()
origins = [
"http://moodmap.app",
"http://localhost:3000/dashboard/MoodMap",
"http://localhost:3000",
"http://localhost",
"http://localhost:8080",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
max_age=3600,
)
I am running the fastapi code in a docker container as well btw
As per Documentation
The Response object, in turn, does not directly contain the actual JSON response body but is instead a representation of the entire HTTP response. So, to extract the JSON body content from the Response object, we use the json() method, which returns a second promise that resolves with the result of parsing the response body text as JSON.
.json() is an async method (it returns a Promise itself), so you have to assign the parsed value in the next .then(). So your code can be changed like this.
function fastApiRequest(path) {
let res;
fetch(`${path}`)
.then((response) => response.json())
.then((data) => (res = data))
.then(() => console.log(res));
return res;
}
response = fastApiRequest('https://proton.api.atomicassets.io/atomicassets/v1/accounts?limit=10');
console.log('response')
If you want to use async/await approach, below is the code.
async function fastApiRequest(path) {
try {
const response = await fetch(path);
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
}
async function test() {
console.log(await fastApiRequest('https://proton.api.atomicassets.io/atomicassets/v1/accounts?limit=10'))
}
test()
first you need to parse the response into json if it's a json API.
function fastapiRequest(path) {
return fetch(`${path}`)
.then((response) => {
return response.json();
});
}
you need to 'await' for the rsponse
you need to write the below code in an async function
const xxxx = await fastapiRequest(
`http://0.0.0.0:8008/xcascasc/Dexaa/Emo.json?Magic=Dexxaa&emotion=expressions`
);
When you make an http request using fetch in javascript it will return a Promise, it's not stuck it's just need to be resloved, you can resolve it just like the above code with async await, or you can use the .then(() => { /* code... */ }) function, you can also use .catch(() => { /* handle error... */ }) function to handle errors.
In Your curl you use x_token as header variable, if it's required you need to pass a header with your path too. All other answers are valid too.
I am trying to get data from server via axios.post().
Decided to use POST and not GET because I want to send an array with ids to look up in the database, which might be too large to fit in GET query params.
I managed to send an array with ids in the body of the POST. This reaches my server. I can successfully find the items in the data base. The items are then returned in the response. The data shows up in Chrome devtools > Network (status 200). I also get the right stuff back when sending a request manually using Postman.
Everything seems to be working fine, but the response does not arrive in my data variable in the axios function.
I spent the day trying out the solutions to all the similar answers here. Nothing worked...
I also tried GET and sending the ids in query params instead, which gives the same error. I suspect I am doing something wrong with async/await because I am getting this "intermediate value" thingy.
Thanks in advance for the help.
CLIENT axios functions
const url = 'http://localhost:5000';
export const getStuff = Ids => {
axios.post(
`${url}/cart/stuff`,
{
Ids: Ids,
},
{
headers: {
'Content-Type': 'application/json',
},
}
);
};
CLIENT actions
import * as api from '../api';
export const getStuff = Ids => async dispatch => {
try {
// Ids is an array like ["5fnjknfdax", "5rknfdalfk"]
const { data } = await api.getStuff(Ids);
// this gives me the error in the title, data never comes through
//dispatch(-dolater-);
} catch (error) {
console.log(error);
}
};
SERVER controllers
export const getStuff = async (req, res) => {
try {
const { Ids } = req.body;
const stuff = await STUFF.find().where('_id').in(Ids);
console.log('SERVER', stuff);
// this works until here. request comes through and
// I can successfully find the stuff I want in the database
res.status(200).json(stuff); // this also works, response is being sent
} catch (error) {
res.status(404).json({ message: error });
}
};
SERVER routes
router.post('/cart/stuff', getStuff);
You have some extra curly braces here (or a missing return, depending on how you look at it). When you use a lambda (arrow function) with curly braces, you have to explicitly return a value or else it will return undefined. Change your code from this:
export const getStuff = Ids => {
axios.post(...);
};
to one of these:
// Option 1
export const getStuff = Ids => {
return axios.post(...);
};
// Option 2
export const getStuff = Ids => axios.post(...);
Either format will return the actual axios promise, instead of the default undefined.
export const fetchPost = () => {
return axios.get(url);
};
This works for me!!
Once that puppeteer goes to a certain url, I want that it listens to all the requests that are made, then find a specific request and return its response. The response should be a json object.
I managed in listening to all the requests and intercepting the desired one, but I don't know how to get its response. Here's my attempt: I get the error TypeError: Cannot read property 'then' of null.
Any suggestion?
page.on('request',async(request)=>{
console.log(request.url())
if (request.url().includes('desiredrequest.json')){
console.log('Request Intercepted')
request.response().then(response => {
return response.text();
}).then(function(data) {
console.log(data); // this will be a string
alert(data)
});
}
request.continue()
})
Since the response may have not arrived yet, the better method would be listening on the response event and get the request object from it.
page.on('response', async(response) => {
const request = response.request();
if (request.url().includes('desiredrequest.json')){
const text = await response.text();
console.log(text);
}
})
You might wanna use the "requestfinished" event instead of the "request" one.
page.on('requestfinished', async (request) => {
const response = await request.response();
const responseHeaders = response.headers();
let responseBody;
if (request.redirectChain().length === 0) {
// Because body can only be accessed for non-redirect responses.
if (request.url().includes('desiredrequest.json')){
responseBody = await response.buffer();
}
}
// You now have a buffer of your response, you can then convert it to string :
console.log(responseBody.toString());
request.continue()
});
I've written a function to send a http put request to update some data but it says, that it is not recieving any data:
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data).map(
response => response.json().data as Human,
error => console.log(error)
);
}
After I've changed my function to the following, it is working:
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data).map(() => human);
}
Could someone explain me, why the first function is not working but second is working?
Observables are lazy, you need to be subscribed to them for them to work and retrieve anything. Did you subscribe to your method? Example:
methodToUpdateHuman(human): void{
...
this.updateHuman(human).subscribe((response) => {
//do something with the response
console.log.("Response is: ", response);
},
(error) => {
//catch the error
console.error("An error occurred, ", error);
});
}
I suggest you read through the Angular Tour Of Heroses, it's based in angular 2 and most of the functionality is functional in angular 4, there is a section dedicated to http requests: https://angular.io/tutorial/toh-pt6
In the second example you are not returning the response within the map, you are returning the human that was originally passed in.
So, basically you are creating an illusion that it is working, when it isn't.
Probably best to test your API with something like PostMan, to see if you can get it working with that first.
You use map method incorrectly, read more about this method in documentation: http://xgrommx.github.io/rx-book/content/observable/observable_instance_methods/map.html
If you want receive response from server your code should look like that:
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data).subscribe(
response => response.json().data as Human,
error => console.log(error)
);
}
You can use map method if you want to modify server response(map some objects to other structures etc.):
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data)
.map(response => { return response.json() }) // you can get json response here
.subscribe(
response => response.data as Human, // -- change here --
error => console.log(error)
);
}
map method returns Observable object, so you can subscribe that and wait for response, error or simple complete method(third parameter of subscribe()):
http://xgrommx.github.io/rx-book/content/observable/observable_instance_methods/subscribe.html
I want to fetch my Json file in react js, for this I am using fetch. But it shows an error
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
What could be the error, i am getting no clue. I even validated my JSON.
handleGetJson(){
console.log("inside handleGetJson");
fetch(`./fr.json`)
.then((response) => response.json())
.then((messages) => {console.log("messages");});
}
My Json (fr.json)
{
"greeting1": "(fr)choose an emoticon",
"addPhoto1": "(fr)add photo",
"close1": "(fr)close"
}
Add two headers Content-Type and Accept to be equal to application/json.
handleGetJson(){
console.log("inside handleGetJson");
fetch(`./fr.json`, {
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then((response) => response.json())
.then((messages) => {console.log("messages");});
}
The solution that worked for me is that:-
I moved my data.json file from src to public directory.
Then used fetch API to fetch the file.
fetch('./data.json').then(response => {
console.log(response);
return response.json();
}).then(data => {
// Work with JSON data here
console.log(data);
}).catch(err => {
// Do something for an error here
console.log("Error Reading data " + err);
});
The problem was that after compiling react app the fetch request looks for the file at URL "http://localhost:3000/data.json" which is actually the public directory of my react app. But unfortunately while compiling react app data.json file is not moved from src to public directory. So we have to explicitly move data.json file from src to public directory.
This error can be received but be aware it can be a red herring to the real issue. In my case, there wasn't an issue with the JSON as the error states, but rather a 404 was occurring that it could not pull the JSON data to process in the 1st place thus resulting in this error.
The fix for this was that in order to use fetch on a .json file in a local project, the .json file must be accessible. This can be done by placing it in a folder such as the public folder in the root of the project. Once I moved the json file into that folder, the 404 turned into a 200, and the Unexpected token < in JSON at position 0 error was resolved.
I was getting the same error, for me, it was because API was just returning a string however in fetch call I was expecting json :
response => response.json()
Returning json from API resolved the issue for me, if your API is not supposed to return json then simply don't do response.json()
I also had the same issue when trying to fetch the data from "/src" folder. Moving the file into the "/public" solved the problem for me.
I had the same issue with fetch and decided to switch to axios. Fixed the issue right away, here's the code snippet.
var axios = require('axios');
var config = {
method: 'get',
url: 'http://localhost:4000/'
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
I had the same issue although I was requesting data from another web server and not locally. The response status code was 200 but I still didnt get the data, even though it was sent in JSON format by default. The (simple) problem was that I had forgot to include 'https://' in the url, so instead it used the local host in the beginning.
on your Promise response
you requested
response.json()
but this works well if your server sends json response in return
especially if you're using Node Js on the server side
So check again and make sure your server sends json as response
as said if its NodeJS the response could be
res.json(YOUR-DATA-RESPONSE)
I confirm some methods proposed here that also worked for me : you have to put your local .json file in your public directory where fetch() is looking for (looking in http://localhost:3000/)
for example : I use this fetch() in my src/App.js file:
componentDidMount(){
fetch('./data/json-data.json')
.then ( resp1 => resp1.json() )
.then ( users1 => this.setState( {cards : users1} ) )
}
so I created public/data/json-data.json
and everything was fine then :)
Sometime you API backend could not respect the contract, and send plain text (ie. Proxy error: Could not proxy request ..., or <html><body>NOT FOUND</body></html>).
In this case, you will need to handle both cases: 1) a valid json response error, or 2) text payload as fallback (when response payload is not a valid json).
I would suggest this to handle both cases:
// parse response as json, or else as txt
static consumeResponseBodyAs(response, jsonConsumer, txtConsumer) {
(async () => {
var responseString = await response.text();
try{
if (responseString && typeof responseString === "string"){
var responseParsed = JSON.parse(responseString);
if (Api.debug) {
console.log("RESPONSE(Json)", responseParsed);
}
return jsonConsumer(responseParsed);
}
} catch(error) {
// text is not a valid json so we will consume as text
}
if (Api.debug) {
console.log("RESPONSE(Txt)", responseString);
}
return txtConsumer(responseString);
})();
}
then it become more easy to tune the rest handler:
class Api {
static debug = true;
static contribute(entryToAdd) {
return new Promise((resolve, reject) => {
fetch('/api/contributions',
{ method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify(entryToAdd) })
.catch(reject);
.then(response => Api.consumeResponseBodyAs(response,
(json) => {
if (!response.ok) {
// valid json: reject will use error.details or error.message or http status
reject((json && json.details) || (json && json.message) || response.status);
} else {
resolve(json);
}
},
(txt) => reject(txt)// not json: reject with text payload
)
);
});
}
Try converting the response to string and then parse it to JSON. This solves the error for me. Below is the code for the same.
let resp = JSON.stringify(response);
res = JSON.parse(resp);
It may come when the API(you are consuming) is not sending the corresponding JSON.
You may experience the response as 404 page or something like HTML/XML response.
I had the .json file in src folder. Simply moved it in the public folder and it worked
I struggled with the same issue but then found a solution after doing some research.
The issue sometimes arises from a typing error. Your console lets you know the type of error.
Here's is how I found out: In settings.py I wrote a double underscore: CORS__ORIGIN_ALLOW_ALL = True instead of
CORS_ORIGIN_ALLOW_ALL = True.
The issues persisted and I changed this 'the API Fetch method' and it worked just fine:
refreshList() {
fetch(process.env.REACT_APP_API+ "department")
.then((response) => response.json())
.then((data) => {
this.setState({ deps: data });
});
}
to:
refreshList() {
fetch("http://127.0.0.1:8000/" + "department")
.then((response) => response.json())
.then((data) => {
this.setState({ deps: data });
});
}
For me, I was making a call with fetch from a new computer and I forgot to add the env file to populate the process.env.REACT_APP_URL and process.env.REACT_APP_API_KEY fields. Adding back the .env file resolved the issue.
Add "method: 'GET'"
let query = {
method: 'GET',
headers: {
authToken: token,
"Content-Type": "application/json",
},
};
With datas in public/datas/datas.json :
export default class App extends React.Component {
constructor(props) {
super(props);
}
async componentDidMount() {
const response = await fetch("datas/datas.json");
const datas = await response.json();
console.log(datas);
}
...
At first, add the line of code that is given below at the top :
const port = process.env.PORT || 3000;
make sure your fr.json inside public folder.
then write the code as given below:
fetch(`http://localhost:${port}/fr.json`)
.then((response) => response.json())
.then((messages) => {console.log("messages");});
I was getting the error.
I simply added "proxy" in my package.json and the error went away.
The error was simply there because the API request was getting made at the same port as the react app was running. You need to provide the proxy so that the API call is made to the port where your backend server is running.
Mostly this is caused with an issue in your React/Client app. Adding this line to your client package.json solves it
"proxy": "http://localhost:5000/"
Note: Replace 5000, with the port number where your server is running
Reference: How to get create-react-app to work with a Node.js back-end API