React state not updating after a post request? - node.js

I'm trying to send a post request to my backend with axios, and my backend gets the values with no problem, but I want to set a state of (sent) to true when the post request is "successfully sent", I put the setSent(true) in the .then() after the axios request. but when I send the request the state isn't updated! what could be the problem? backend gets the values and works fine though... see code bellow:
const submitHandler = () => {
axios
.post(
"/sendFeedback",
qs.stringify({
name,
email,
text,
})
)
.then(() => {
setSent(true) // doesn't work (the state is still false)
})
.catch((err) => {
err && setError(true) // works just fine!
})
}

try
const submitHandler = async () => await axios ...
because it's asynchronous process and returns a promise.

Related

NodeJs, Axios: Value of variable not updating with response from xhr request

I am making an xhr request in nodejs using Axios. And I am trying to save a value from this response to a variable, but it isn't working and I am not sure why.
Code:
let redirectUrl = 'placeholder'
axios.get(url)
.then(res => {
redirectURL = res.url
console.log(res.url, "HERE")
})
.catch(err => console.log(err))
return res.render('index',{url: redirectURL})
I have tried declaring redirectUrl in both global as var and local scope, but the value isn't changing, on index when I console log this value, it logs placeholder. index is index.jsx as I am using jsx as the template engine.
Please let me know if I should provide any more information.
Thank You in advance.
axios.get is an async call, so your return will use the original (placeholder) value instead of the new one. Normally to solve this kind of asynchronicities i use async/await
async function getRedirectURL(url) {
try {
const res = await axios.get(url);
// Note that if you want some return value from axios call you access it by res.data
console.log('res.url :', res.url, ". res.data:", res.data);
return res.render('index',{url: res.data.url});
} catch (err) {
console.log(err);
throw err;
}
}
Axios is a promise-based HTTP client, So when javascript engine executes your code, it moves axios call to web API from callstack (line# 2) and then it starts to execute the last line return res.render('index',{url: redirectURL}) where redirectURL value is placeholder. You have to write all the logic in promise then method, like
axios
.get(url)
.then((data) => res.render("index", { url: data.url }))
.catch((err) => {
// error response
console.log(err);
});

How to fix an endpoint test that returns 404 status code rather than 200 using express, jest and supertest

My end goal is that I want to be able to create a test that satisfies the following statement:
verify that requests to valid URLs return a 200 HTTP status code
A valid URL for example would be /about-page or /jobs, basically any directory that I add in my content folder that contains a file with the extension /index.md.
This is my code so far:
app.js
const readFilePromise = util.promisify(fs.readFile)
app.get('/*', (req, res) => {
readFilePromise(path.join(__dirname, 'content', req.url) + '/index.md', 'utf8')
.then(data => {
convertData(data, res)
})
.catch(err => {
res.status(404).send('Page doesn\'t exist!')
})
})
const convertData = (data, res) => {
const convertedData = md.render(data)
readFilePromise(path.join(__dirname, '/template.html'), 'utf8')
.then(data => {
data = data.replace(/\{\{content\}\}/, convertedData)
res.send(data)
})
.catch(err => {
console.log(err)
})
}
app.listen(3000)
module.exports = app
After reading this article, it mentions that
Requests are asynchronous, which means you must be able to conduct asynchronous tests.
So I wrote the following test:
app.test.js
const app = require('./app.js')
const request = supertest(app)
const supertest = require('supertest')
it('Gets the test endpoint and returns a 200 status', async done => {
const res = await request.get('/*')
expect(res.status).toBe(200)
done()
})
When I run the test, it fails with a 404 status, rather than returning a 200 status. I thought this might be due to my app.js not being in the async/await style, so I changed app.js to:
const readFilePromise = util.promisify(fs.readFile)
app.get('/*', async (req, res) => {
try {
await readFilePromise(path.join(__dirname, 'content', req.url) + '/index.md', 'utf8')
} catch (err) {
res.status(404).send('Page doesn\'t exist!')
}
try {
const convertedData = md.render(data)
await readFilePromise(path.join(__dirname, '/template.html'), 'utf8')
data = data.replace(/\{\{content\}\}/, convertedData)
res.send(data)
} catch (err) {
console.log(err)
}
})
app.listen(3000)
module.exports = app
I tried running the test again, but it still fails with a 404. I think my set up within app.test.js is wrong, but I'm not sure exactly what, as I've tried using the various set ups as the article. How would I fix this?
Separately, when I try going to a URL using the async/await style in app.js, I get a ReferenceError: data is not defined error, but I'm not sure how to define data in the async/await format.
I explained here how to set up app for the test environment: supertest not found error testing express endpoint
You did not mention how you set the database environment, make sure your database is not empty. Then make your get request. but just checking status for get request is not enough because if your db is empty you will still get 200.
const response = await request(app).get("/route").send().expect(200);
expect(response.body.length).toBeGreaterThan(0)
Better approach would be connect to a different database, post your data first and then check the response
const response = await request(app).get("/api/tickets").send().expect(200);
expect(response.body.length).toEqual(2); // if you post two items
Also before you every test make sure you start with empty database inside beforeEach()

Async Request to API return undefined in Jest

I am quiet new to testing, and specifically to Jest.
I am following several tutorials in which they handle asynchronous code in the manner I am attempting. My code seems to work when I am making a custom Promise that resolves with dummy data. But when I try to use axios to fetch from an external API, Jest gets as a response undefined.
// functions2.js
const axios = require("axios")
const fetch = () => {
axios.get("https://jsonplaceholder.typicode.com/users")
.then(res => res.data)
.catch(err => err);
}
module.exports = fetch;
// functions2.test.js
describe("async operation", ()=>{
it("should be defined", ()=>{
expect(fetch).toBeDefined()
}); // Passed
it("should fetch", async () => {
expect.assertions(1);
const data = await fetch();
expect(data).toBeTruthy();
}) // Did not pass, data is undefined
it("should fetch, using promises", () => {
expect.assertions(1);
return fetch().then(data => {
expect(data).toBeTruthy();
}) // Did not pass, got 0 assertions
})
})
In one tutorial I encountered that this has something to do with Jest running through Node.JS, but I don't know how to handle it because I don't know node.js.
Also, I followed a tutorial by Traversy Media, cloned his Git repo (https://github.com/bradtraversy/jest_testing_basics) and had the same problem (though in the video it worked)
The problem is because you are not returning the promise from fetch.
Update your functions2.js to something like:
const fetch = async () => {
return axios
.get("https://jsonplaceholder.typicode.com/users")
.then(res => res.data)
.catch(err => err);
};

Using Node and Express, How to Call remote API from inside server.get(..)

Because of CORS problems, I want to call an external REST API from inside my node express server. That is, I have code like this that obviously does not work because it does not return.
How can I make this work and return the results of my external call?
const server = express();
server.put('/callme',(req,res) => {
axios
('http://weather.com/restapi', 'put', { zip: 10530 })
.then((resp: any) => {
console.log(' success' + resp.data);
})
.catch(function(error: any) {
console.log(error.message);
});
}
Axios returns a Promise which is resolved in the .then(). In order to get the response data back to the client you need to return it with res.send().
const server = express();
server.get('/callme', (req, res) => {
axios
.get('http://weather.com/restapi?zip=10530')
.then((resp: any) => {
res.send(resp.data);
})
.catch(function(error: any) {
console.log(error.message);
});
}
It would be a good idea to cache the weather API response for a period of time and serve the cached response for subsequent requests.

Sending data to express backend

I am learning how to use express, and I am able to get data, but I'm having more trouble figuring out how to send data back to update the backend. Here is an example of what it looks like.
server.js
app.route('/animals')
.get(function (req, res) {
res.send({ Cat, Dog, Bear, Wolf, etc... });
})
.patch(function (req, res) {
console.log('patch is working!')
// unsure of how to get this called with react or use req here
})
react front end
componentDidMount(){
this.callApi()
.then(res => this.setState({ name: res[this.state.animal].name }) )
.catch(err => console.log(err))
}
callApi = async () => {
const response = await fetch('/animals');
const body = await response.json();
if (response.status !== 200) throw Error(body.message);
return body;
};
This works flawlessly when getting the data, so i have .get down, but I am running into walls trying to use .patch. I can't get the console.log to fire,
let alone send it data! (lets say instead of trying to get the animal name, I'm trying to update it's name.) Any ideas? Thanks ahead of time.
The fix in this case was adding JSON.stringify in addition to what RishikeshDhokare shared! I hope this can help someone else down the line.
const response = await fetch('/animals', {
method: 'PATCH',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({ name: 'kitten})
});

Resources