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})
});
Related
I've had a blockage since last night and I still don't understand, let me explain.
I use React, Mongo DB, and NodeJs, and axios for my API calls
I created a route to retrieve the info of a user, when I test the route with PostMan, I have the user info so everything works as it should, only when I make the api call from my front, my res.data returns "null", so I think it's coming from my api call, but I can't find what's wrong.
I am attaching some screenshot, thank you in advance:
API call :
function Post() {
axios({
method: "get", url: "http://localhost:4000/api/auth", credentials: true,
params: {
userId: "62f045f5253a960077a8ff3f"
}
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}
Function back getOneUser:
exports.getOneUser = (req, res, next) => {
userModel.findOne({_id: req.params.userId}).select('-password -email')
.then(post => res.status(200).json(post))
.catch(error => res.status(404).json({error}))
}
In express, use req.query instead of req.params.
This post might clarify the differences between them
This is a course quiz and this is the most basic information I need in order to create a React app. But while the endpoint URL is correct, the page "/products" returns a "400" error when I try to request the product list. The instructions I'm given are:
Obtain a list of products with
Route: /products
Body: Array
method: POST
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
My index.js
...
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`);
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
in Postman
I use http://localhost:4000/products
and pass a Body / Raw /JSON:
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
But I can't get in! I am not seeing something obvious because this is the entry point to a very long and complex quiz. Thanks
What I see from the code is a recursive long call.
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`); // calling the same end point
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
You should do something like this:
app.post(`/products`, async (req, res) => {
// do your logic
// when you pass body from postman on this endpoint
// you will receive the body here and save it to DB
// or do the manipulation and then send back the response
res.status(200).json(req.body.data);
});
I highly recommend you to first follow through some tutorials to understand how API works and how to create simple API using Node.js.
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()
The Problem
I deployed a create-react-app webapp to aws ec2. It's used to display data from a database and send data to it. I use ExpressJS, CORS and MySQL.
With the following code i fetch the corresponding URL and the server.js sends back the database content. Until here, everything works fine.
getBets = _ => {
fetch("http://ec2***.amazonaws.com
.then(response => response.json())
.then(response => this.setState({bets: response.data}))
.catch(err => console.error(err))
};
The problem begins when sending data to the database with the following code:
addBet = _ => {
const { bet } = this.state;
fetch(`http://ec2***.amazonaws.com/bets/add?name=${bet.person_name}&bet=${bet.time_bet}`)
.then(response => response.json())
.then(this.getBets)
.catch(err => console.error(err))
};
On click the addBet-function populates the db, but in chrome I following error:
GET http://ec2***.amazonaws.com/bets/add?name=Peter%20Pan5&bet=10:17%205 net::ERR_EMPTY_RESPONSE
and
TypeError: Failed to fetch
Regarding chrome dev-tools, the first error corresponds to the fetch in the addBet function and the second error to the catch part.
On the server side I've the following code for processing the fetch:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES("${name}", "${bet}", CURTIME())`;
connection.query(INSERT_BET, (err, res) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I want to mention, that the res paramter in the app.get part is unused. That tells me my IDE.
After a lot of hours digging deeper in the topics of expressJS and the fetch api, I guess, that the app.get part doesn't send a response to the server. But the fetch need some response.
My Question
How do I have to change the code in the app.get part to send a proper response back to the server?
AND
Am I right with my guess?
In MYSQL when you do an insert query you get back err,results and fields in the callback function like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error,
results, fields) {
if (error) throw error;
console.log(results.insertId);
});
You have used the parameter res for result and then you have used res.send() which now corresponds to that res parameter in the callback function and not the res object.Rewrite it like this:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES(?,?,?)`;
connection.query(INSERT_BET,[name,bet,CURTIME()] ,(err, result) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I have also used prepared statement in place of normal sql queries. These are used to prevent sql injections. I hope it will work now.
im getting problem with passing data in to delete request with Vue-resource. Server is reciving blank object without data. There is some code:
Front-end with Vue.js and Vue-resourcer
deleteArticle: function(tit){
console.log(tit);
this.$http.delete('http://192.168.0.52:8080/article',{'title':'123'}).then((res)=>{
this.refresh();
console.log(res.data);
}).catch((e)=>{console.log(e)});
}
Back-end with node.js route using express.js API.
app.delete('/article', (req,res)=>{
var body = _.pick(req.body,['title']);
console.log(req.body); //printing blank object from request
Article.findByTitleAndRemove(body.title).then((doc)=>{
res.status(200).send(`Deleted Article with title ${doc.title}`)
}).catch((e)=>{
console.log(e);
res.status(400).send(e);
})
})
This route works with postman.
Try this:
this.$http.delete('http://192.168.0.52:8080/article', { params: { title: 123 } }).then(res => {
this.refresh();
console.log(res.data);
}).catch((e)=>{console.log(e)});
Update: this is how this works for me in node:
app.delete('/article', (req, res) => {
console.log(req.query.title);
});