Problems with Id at the end of a restful api - javascript

The fetch works if I just use the URL without /"some ID" at the end, but I want to target a sepcific id. I think the problem is from the clientside, because router.patch() works with postman (using the same URL). However I am not able to send any data to the server because the fetch cant find the URL (404). Or maybe fetch doesent work with patch requests, idk?
client-side:
async function update(){
const fromInp = { username: inp.value };
let param = {
method: 'PUT', // or 'POST'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(fromInp),
}
await fetch(`http://localhost:8080/api/userModel/5e4ec9567566adade97df11e`, param)
}
server-side:
router.patch('/:postId', async (req,res)=>{
try{
const update = await User.updateOne(
{_id: req.params.postId},
{ $set: {username: req.body.username}})
res.json(update)
} catch(err){
res.json({message: err})
}
})

Set the method property to be the text: 'PATCH'.

Related

Error trying to POST request from react to nodeJS

I'm trying to post a new object to my mongodb collection which is handled on my backend server, but the values from my request body are not passed to it.
I can guarantee that the object is created. The problem is that all the object values are empty.
I also guarantee that the nodejs code works correctly. The first thing I did was create a web application just using nodeJS and from that page I can create a new object normally.
But now I'm creating a frontend page using react and I'm not sure why my frontend page's post request doesn't work as intended
react code:
const handleSubmit = async (event) => {
event.preventDefault();
const requestOptions = {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name:nome,
cnpj:cnpj,
email:email,
number:telefone,
seguradora:[seguradora],
index:765756
})
};
try{
const response = await fetch('http://localhost:3001/corretoras',requestOptions)
const data = await response.json()
console.log(data)
console.log(requestOptions.body)
}
catch(error){
console.log('error trying to post',error)
}
};
nodeJS code:
router.post('/',async(req,res)=>{
const lastIndex = await Corretora.find().sort({index:-1}).limit(1).index
const corretora = new Corretora({
name:req.body.name,
cnpj: req.body.cnpj,
email:req.body.email,
number:req.body.number,
seguradora:req.body.seguradora,
index: lastIndex
})
try{
const novaCorretora = await corretora.save()
res.redirect('corretoras/'+novaCorretora.id)
}
catch{
renderNewPage(res,corretora,true)
}
})
console log from react code:
Found my issue. I didn't type app.use(express.json()) in my server.js

Typescript removes Authorization header from POST and PATCH fetch requests

I've built an API using C# that uses JWT tokens for authorization. On the frontend I store these tokens in local storage and get them, when creating a request. When creating GET or DELETE requests, everything works fine, and using console.log() I can see that fetch options have the Authorization header added. However when using POST or PATCH methods, the Authorization header is missing immediatly after adding it to the object. Here is my request method:
const send = async (apiOptions: ApiParams): Promise<FetchReturn> => {
const accessToken = GetAccessToken()
const options: ApiOptions = {
method: apiOptions.method,
headers: {
Authorization: `Bearer ${accessToken}`
}
}
console.log(options)
if (apiOptions.data) {
options.headers = {
'Content-Type': 'application/json'
}
options.body = JSON.stringify(apiOptions.data)
}
const result = await fetch(`${getUrl()}/${apiOptions.path}`, options).then(res => res).catch(err => err)
if (!result.ok) {
if (IsExpired()) {
const refreshResult = await fetch(`${getUrl()}/api/user/refresh`, {method: 'POST', headers:{
'Content-Type': 'application/json'
}, body: JSON.stringify(GetRefreshRequest())}).then(res => res).catch(err => err)
if (refreshResult.ok) {
Login(JSON.parse(await refreshResult.text()))
return await send(apiOptions)
} else if (refreshResult.status === 401) {
Logout()
window.location.reload()
return { code: 0, text: ""}
}
}
}
const text = await result.text()
return { code: result.status, text: text }
}
I suppose that in apiParams for POST you have property 'data' assigned, and later you have if-condition that completely replaces request headers object.
Change it to:
options.headers['Content-Type'] = 'application/json';
To keep authorization in headers
The first time check your apiOptions.data
i think , its null when you call POST/Patch request
Just put console.log("...") In the if statement , Then try for resolve your Error
If your problem not resolved, put a replay under my post

Passing value from backend nodejs to frontend react native

My front end is done in React Native and backend in nodejs. It is an application that asks the user to register (email, password, name, email, ...) and then the data is sent to a database (mongodb) using mongoose.
In my front end; when the user presses the button SignUp, it will call a function names "Submit" that you can find below:
const Submit = async (fname, email, pwd, confpwd) => {
if (String(pwd).localeCompare(String(confpwd)) == 0) {
let result = await fetch('http://127.0.0.1:2000/api/user/register', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(
{
name: fname.fname,
email: email.email,
password: pwd.pwd
}
)
})
console.log("RESULT : " + JSON.stringify(result))
} else{
console.log('NOT SAME PASSWORD')
}
};
It just takes in the firstname, email and password entered by the user and uses fetch to post it to the API. Everything works, except the last line : console.log("this is the result : " + JSON.stringify(result)). It always returns an empty json.
The register route in my backend is the following:
//REGISTER
router.post('/register', async (req, res) => {
//Check the input of the user before we make a user
const {error} = registerValidation(req.body)
if (error) {
console.log('Error1')
return 'Error1'
}
console.log('1&')
//Check if the user is already in the database
const emailExist = await User.findOne({email : req.body.email});
if(emailExist) {
console.log('Error2')
return 'Error2'
}
console.log('2&')
//Hash the password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt)
console.log('3&')
//Create a new user
const user = new User({
name: req.body.name,
email: req.body.email,
password: hashedPassword
})
console.log('4&')
//user.save();
try{
const saveUser = await user.save();
res.send(saveUser);
console.log('5&')
}catch(err){
res.send(err)
}
});
Before saving it to the databse it checks the validation and if the email already exists in the database.
It successfully sends the data to the database when the first two conditions are met and if email is already used and the validation format is not correct it does not put it in the dataabse.
However, when the validation format is not correct or the emaoil is already used, I would like my fetch in my front end to let me know. So I thought that putting my fetch in a variable it would output something if it did not work. However, it always sends back an empty json even when the fetch did not work. So, how can I pass a variable from my backend to my frontend ?
Normally in postman this is what I receive when the email already exists. How can I receive this on my frontend ?
On your backend,
You should return a valid HTTP status code and json payload in order to be correctly understood by your front-end.
For invalid inputs you can return a 400 Bad Request with a proper json description and return 200 OK for valid responses.
// for errors
res.status(400).send({error: 'Email already exists' })
// for successful responses
res.status(200).send({result: 'success' })
In your front-end, then you can parse this status code to understand if it is a valid / invalid request and parse payload to show any proper message to your users:
const Submit = async (fname, email, pwd) => {
try {
let response = await fetch('http://127.0.0.1:2000/api/user/register', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(
{
name: fname.fname,
email: email.email,
password: pwd.pwd,
},
),
});
const statusCode = response.status;
const { error, result } = response.json();
// do whatever you want with this info here
} catch (err) {
console.log(err);
}
};
Also, keep in mind that since fetch is running asynchronously, you should use await prefix in an async function like above or use Promises:
fetch returns a promise you need to handle it use async/await
const Submit = = async (fname, email, pwd) => {
const body = JSON.stringify({
name: fname.fname,
email: email.email,
password: pwd.pwd
})
const headers = {
Accept: 'application/json',
'Content-Type': 'application/json',
}
const settings = {
method: 'POST',
headers,
body
};
try {
const fetchResponse = await fetch(`http://127.0.0.1:2000/api/user/register`, settings);
const data = await fetchResponse.json();
return data; // your response data
} catch (e) {
console.log(e)
return e; // handle your error here
}
}
fetch API in submit function is async means console.log() get execute before fetch complete.
you can use asyn/await to get fetch response and get that response to console.log().
// async function
async function fetchAsync () {
// await response of fetch call
let response = await fetch('https://api.github.com');
// only proceed once promise is resolved
return response;
}

How to use the GET and POST method in the same endpoint using nodejs / express

Problem
Hello,
I would like to know how I can create an Endpoint that first uses the POST method to login and obtain the token and then use that Token and use it in a GET method to access some data.
As you will see in the code, I currently have the logic of the POST apart and the GET apart, but my intention is to be able to have an endpoint that uses both methods.
The idea would be that after the POST method returns the token to me, I can use it later in the GET method.
I will appreciate your help and your prompt response!
code
app.post('/api/datas/login', async(req, res) =>{
const url = '...';
const options = {
email: process.env.EMAIL,
password: process.env.PASSWORD
}
const call = await axios.post(url, options)
const token = call.status === 200 ? call.data.token : null;
res.send({
status: call.status,
message: 'Logged In'
})
});
app.get('/api/datas/alldata', async(req, res) =>{
try {
const url = '...'
const call = await axios.get(url,{
headers: {
"Authorization" : `Bearer ${token}` //I need to use the token value from the POST method here!
}
});
const data = call.status === 200 ? call.data : null;
console.log(data);
res.status(200).json(data);
} catch (error) {
res.status(500).send({ message: error });
}
})
Yes, it should be possible (though not recommended) if you use app.all() instead of post() or get().
You can get the method of the request and act accordingly by looking at req.method.
For more info: https://expressjs.com/en/guide/routing.html

Add parameters to post request using js on client side

I'm developing a "TODO" app using node.js and mongodb.
I'm trying to post a new task from the client but I didn't success to pass parameters to the server and from there to the database.
Client code:
<script>
function addData(item, url) {
var text = document.getElementById("myTask").value;
return fetch('/todos',{
method: 'post',
body: text
}).then(response => response.json())
.then(data => console.log(data));
}
</script>
Server code:
app.post('/todos',(req,res) =>{
console.log("\n\n req.body is: \n\n",req.body);
var todo = new Todo({
text: req.body.text});
todo.save().then((doc) =>{
res.send(doc);
console.log(JSON.stringify(doc,undefined,2));
},(err) =>{
res.status(400).send(err); //400 = unable to connect
console.log("Unable to save todo.\n\n\n" , err);
});
});
And the problem is that the client doesn't send the body to the server,
and the body is null on the server side:
See the logs here
(as you can see: req.body = {})
In the js code, I tried to pass the body parameter but I guess I did something wrong so I want to know the best way to pass parameters back to the server (not only the body but text, time and etc)
Thank in advance,
Sagiv
I think that you are missing something. Try to use name of param
body: JSON.stringify({data: text})
OR
read here Fetch: POST json data
I used this code:
(async () => {
const rawResponse = await fetch('https://httpbin.org/post', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({a: 1, b: 'Textual content'})
});
const content = await rawResponse.json();
console.log(content);
})();
and now I succeeded to pass data to the request.
Thanks everybody

Categories

Resources