Fetch API body not working - javascript

It is a very simple fetch api but for some reason I dont know why the body is not working. here is the code.
<label id="msg"></label>
<label id="msg2"></label>
<script type="text/javascript">
const myRequest = new Request('some url', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({"email" : "email",
"password" : "password"}),
mode: 'no-cors'});
const myMethod = myRequest.method; // POST
const bodyUsed = myRequest.bodyUsed; // true
fetch(myRequest)
.then(response => {
if (response.status === 200) {
return response.json();
} else {
//throw new Error('Something went wrong on api server!');
}
})
.then(response => {
document.getElementById("msg").innerHTML = response;
document.getElementById("msg2").innerHTML = bodyUsed+" "+myMethod;
}).catch(error => {
document.getElementById("msg").innerHTML = error;
});
</script>
Is there anything I am doing wrong? I have stringify the body, changed the header but still when it runs, it shows false in msg2 label (which is nothing but just the body part of the request, just to be sure). which means the body is actually NaN. where is the problem and whats the solution?

mode: 'no-cors'
This means I do not want to do anything that would require the server to use CORS to grant permissions; do not throw CORS related errors.
Reading the response across origins requires the server grants permissions with CORS.
You said you weren't going to do that, so fetch does not try to make the body available to you.
(You are also prevented from doing anything that would require a preflight request, such as setting the Content-Type request header to JSON.)
Don't set the mode to no-cors.

Related

How can I update the message body using gmail API in javascript

I have got the message body. Now I want to update it according to my needs. I am using this login/code. but it says 400 error. I think issue is in body parameter of the request. Would you please help me there?
var token = localStorage.getItem("accessToken");
var messageId = "18514426e2b99017";
async function updateMessageBody() {
var updatedBody = "Hello,\n\nThis is the UPDATED message body.\n\nBest regards,\nJohn";
const API_KEY = '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-CXIk';
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
const response = await fetch(`https://gmail.googleapis.com/gmail/v1/users/me/messages/18514426e2b99017/modify?key=['API_KEY']`, {
method: 'POST',
headers: headers,
body: JSON.stringify({
raw: window.btoa(unescape(encodeURIComponent(updatedBody)))
})
});
if (!response.ok) {
// throw new Error(`Request failed with status code ${response.status}`);
}
return await response.json();
}
updateMessageBody()
.then(response => {
console.log('Message body updated successfully:', response);
})
.catch(error => {
});
Checking the documentation, it states that a message body can't be altered once it has been created, meaning that once you have already created an email this message can't be changed. You can verify this here.
You can instead update a message draft which is possibly what you are trying to do, however using the endpoint you have in your code this won't be possible and will lead to the error message you are getting, try using instead the users.draft.update method that allows you to modify the content of the draft sitting in your mailbox. Please note as well that using the method users.messages does not have any update method as they only have the modify one's, those methods can only update the labels though so please be aware of that.

Any way to efficiently log if a server exists with JavaScript without CORS?

I've been spending nearly all day just trying to implement a rather simple feature in my React code. The basic idea is checking if a server is reachable, and if it isn't, return a console.log() indicating so. Here's what I have so far:
Relevant Code
const handleLinkRegex = () => {
fetch(LinkInput, { mode: "no-cors" })
.then((response) => {
if (response.ok || response.status === 0) {
console.log("yessir");
} else if (response.status === 404) {
return Promise.reject("error 404");
} else {
return Promise.reject("some other error: " + response.status);
}
})
.then((data) => console.log("data is", data))
.catch((error) => console.log("error is", error));
};
Output
If the link is valid, such as https://mantine.dev/core/input/, the result is yessir, followed with data is undefined.
If the link is invalid and returns a 404, such as https://mantine.dev/core/input/invalidurl, the result is a console 404 error, and yessir, followed with data is undefined, which is the same as if it didn't fail.
What I tried
Using the url-exist library only resulted in a CORS error
Attempted to use a different solution from a stackoverflow question:
const handleLinkVerify = async () => {
fetch(LinkInput, { mode: "no-cors" })
.then((r) => {
console.log("Is reachable");
})
.catch((e) => {
console.log("Is not there");
});
};
Which resulted in every url, no matter if valid or not, to return as Is not there.
Overall, I'm waving the white flag with dealing with a simple issue. It's taking me hours just to catch this 404 error and handle it, and no matter what green checkmark answer I read their solution doesn't work for me, for some reason. I feel like I'm missing something obvious, but I don't know what. Thanks for any help.
Since it is not possible to distinguish a CORS-Error from any other Error, let's say Network-Error, and you can't even read the Status-Code, so you can't tell if the website sent a 404 or any other code, the approach you want to go (checking it on the front-end) is technically impossible. CORS was specifically designed to behave that way. If you want to read more on that: Trying to use fetch and pass in mode: no-cors
Your best bet here would be to do this sort of thing on the backend, since you can just ignore the cors header and just read the data. You could do something like that:
I used express and axios, but you can use whatever you want to.
const express = require("express");
const app = express();
const axios = require("axios");
app.use(express.json());
app.post("/checkStatusCode", async (req, res) => {
const { url } = req.body;
if (url == undefined || typeof url != "string") {
return res.status(400).json({ status: 400, msg: "URL required" });
}
try {
const request = await axios.get(url);
res.status(request.status).json({ url, status: request.status, msg: request.statusText });
} catch (err) {
if (err.response != undefined) {
res.status(err.response.status).json({ url, status: err.response.status, msg: err.response.statusText });
} else {
console.log(err);
res.status(500).json({ status: 500, msg: "Internal Server Error" });
}
}
});
app.listen(5000);
Then you would just call that on your frontend, and check for the Statuscodes:
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({
"url": "https://google.com"
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("http://localhost:5000/checkStatusCode", requestOptions)
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.log('error', error));
If you have trouble with CORS on your backend, there is a npm package for that: https://www.npmjs.com/package/cors
Just require and use it like this:
const cors = require("cors");
app.use(cors());

How to get content-type from the response headers with Fetch

I'm trying to access the returned content-type from my GET request so I can decide the kind of preview I want to like for html maybe pass through an iframe and for a PDF maybe some viewer. The problem is when I do console.log(response.headers) the object returned doesn't have content-type in it but when I check the networks tab the response headers has content-type:html/text. How can I get the content-type from the response headers?
this is how my GET request looks like
const getFile = async () => {
var requestOptions = {
method: "GET",
headers: context.client_header,
redirect: "follow",
};
let statusID = context.currentStatus.ApplicationID;
var response = await fetch(
process.env.REACT_APP_API_ENDPOINT +
"/services/getStatus?ApplicationID=" +
statusID,
requestOptions
);
console.log(response.headers);
if (response.ok) {
let fileHtml = await response.text();
setfileURL(fileHtml);
} else {
alert.show("Someting went wrong");
}
};
The Headers object isn't a great candidate for console.log() since it is not easily serialisable.
If you want to see everything in it, try breaking it down to its entries via spread syntax
console.log(...response.headers)
You'll probably find that you can in fact access what you want via
response.headers.get("content-type")
See Headers.get()

cross origin for amazon lambda function from localhost in gatsby site

I have the following code which works when I run it as a local serverless function with netlify dev, but I need it to run cross origin from a dev server to the hosted server function. I put the function in a aws lambda function but I am getting a cross origin blocked error on my https:dev.website.com, I thought I have the correct headers in the return object so not sure why I am getting a cross origin error.
Any help would be great
const sanityClient = require("#sanity/client");
const client = sanityClient({
projectId: "random-id",
dataset: "production",
useCdn: true,
});
exports.lambdaHandler = async (event, context) => {
var body = JSON.parse(event.body);
//console.log(body.price_id)
try {
const checkPriceId = async (test) => {
const query = `*[_type == "products" && price_id == "${body.price_id}"]`;
const documents = await client.fetch(query, {}); // this could throw
return documents.map((document) => document.sold);
};
var ok = checkPriceId().then((test) => {
return new Promise(function (resolve, reject) {
//console.log(test) // this will log the return value from line 7
console.log(test);
resolve(test);
});
});
var bools = await ok;
// prettier-ignore
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods':'GET, POST, OPTION',
},
body: JSON.stringify({
sold: bools,
}),
};
} catch (err) {
return { statusCode: 500, body: err.toString() };
}
};
This is my request to the function if that helps
var fetchUrl = https://random.executue-api.aws.com/prod/sold //not exact
var fetchData = async function () {
const response = await fetch(fetchUrl, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
price_id: final,
}),
})
.then(res => {
return res.json()
})
.catch(error => console.log(error))
return response
}
Update:
I tried adding cors the way suggested in the answer below, but it failed seen below so I tried manually adding the method response seen after.
I still get a cross domain error. And I have changed the domain so it is now https as well. Really stuck here.
I was looking into this more, and it seems like before it does the actual post it does a cors check at the options method, so I added in the same access control headers, and deployed but did not work. Don't quite get this.
Your headers look ok to me. (note: If you mix HTTP and HTTPS you are most likely to get a mixed content error in the client). If it is ONLY a CORS issue that you are seeing in the console in the web browser, then you might not have configured the API Gateway correctly in AWS.
In AWS, go to API Gateway and you should see something like the below:
Make sure that you enable CORS and then redeploy.
UPDATE:
Just looking at a previous implementation of a lambda function I setup with AWS. The headers I declared were as follows:
headers: {
"Content-Type" : "application/json",
"Access-Control-Allow-Origin" : "*",
"Allow" : "GET, OPTIONS, POST",
"Access-Control-Allow-Methods" : "GET, OPTIONS, POST",
"Access-Control-Allow-Headers" : "*",
"Access-Control-Allow-Credentials" : true
}
Your headers look OK to me though. However, when you created the method in the API Gateway, did you select Use Proxy Lambda Integration? (see screenshot).
Your client side fetch request looks ok. For reference mine was:
const url = 'your url';
const options = {
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
};
fetch(url, options).then(res => res.json());
Unrelated to this issue, but its not advisable to mix Async/Await with .then promise chaining. But this isn't the issue you are having. Just something to note.
Check the values from your Integration Response / try setting them manually for both OPTIONS and POST (and if that works, make sure you are passing through the response correctly from the lambda).
Your POST action should only require the Access-Control-Allow-Origin header. The other two (Access-Control-Allow-Methods, Access-Control-Allow-Headers) belong in the OPTION action. See this writeup, and note the full example exchange for a preflighted request (in grey): https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests

Fetch POST Unexpected end of input Erorr

I'm trying to do a POST request for authentication in Redux and I'm passing email & password as the body but it returns this error in the console:
Uncaught (in promise) SyntaxError: Unexpected end of input
I looked around for the answer and many people suggested that it might be a missing } brace but I looked for it and I don't think it's that.
Here is my fetch function.
export function loginUser(creds) {
let config = {
mode: 'no-cors',
method: 'POST',
headers: { 'Content-Type':'application/x-www-form-urlencoded' },
body: `email=${creds.email}&password=${creds.password}`
};
return dispatch => {
dispatch(requestLogin(creds));
return fetch('http://localhost:4000/api/authenticate', config)
.then(response =>
response.json()
.then(user => ({ user, response }))
).then(({ user, response }) => {
if (!response.ok) {
dispatch(loginError(user.message));
return Promise.reject(user);
} else {
localStorage.setItem('id_token', user.token);
dispatch(receiveLogin(user));
}
});
};
}
The fetch POST method calls the API and I see it in the networking tab and I see the response too but the fetch request stops at .then(response => after the url and config.
It's been two days and still can't find the solution. By the way, this works fine in Postman(chrome extension), so nothing wrong with the API.
Thanks
Answer EDIT: The issue was related to CORS, so for anyone having the same issue as I did.
I solve the same question when I remove
mode: 'no-cors'
from the config.
Anyway you could simplify your snippet code to:
fetch('http://localhost:4000/api/authenticate', config)
.then(response => response.json())
.then(({ user, response }) => {
And you should might add catch method to handle an Error object.

Categories

Resources