Fetch - get HTML text as a response - javascript

I have a problem. I have rate-limit that returns HTML:
const Limiter = rateLimit({
windowMs: 5 * 60 * 1000,
message: "Too many requests created from this IP, please try again later.",
max: 10
})
And I have fetch request in Client side that gets that Message:
const body = { email, password }
const res = await fetch("http://localhost:5000/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(body)
})
const parseRes = await res.json()
if(parseRes.JwtToken) {
localStorage.setItem("JwtToken", parseRes.JwtToken)
setAuth(true)
toast.success("Login successfuly")
} else {
setAuth(false)
toast.error(parseRes)
}
My problem here is that when I get json object back it displays on the screen. But when I get that message object it does nothing. It just shows that failure 429 in the console. My question here is how can I get/display that HTML that returns normally like I would get an JSON object.

So before you parse the JSON check the status
if (!res.ok) {
/* handle the error */
return;
}
const parseRes = await res.json()

Related

Error 400 when using GPT API (in JavaScript)

I keep getting a 400 Error when I try to run my very basic chatbot using the GPT API:
error
Attached is my code; am I doing something wrong with the API key?
const chatHistoryContent = document.querySelector("#chat-history-content");
const chatMessageInput = document.querySelector("#chat-message-input");
const chatMessageSubmit = document.querySelector("#chat-message-submit");
chatMessageSubmit.addEventListener("click", async function () {
const message = chatMessageInput.value;
chatMessageInput.value = "";
// Add the user's message to the chat history
const userMessageDiv = document.createElement("div");
userMessageDiv.innerHTML = `You: ${message}`;
chatHistoryContent.appendChild(userMessageDiv);
// Use the OpenAI GPT-3 API to get a response from the chatbot
const response = await getResponseFromAPI(message);
// Add the chatbot's response to the chat history
const chatbotMessageDiv = document.createElement("div");
chatbotMessageDiv.innerHTML = `Max: ${response}`;
chatHistoryContent.appendChild(chatbotMessageDiv);
});
async function getResponseFromAPI(message) {
const apiKey = "sk-myapikey";
const endpoint = `https://api.openai.com/v1/engines/davinci/jobs`;
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": `application/json`,
"Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: "text-davinci-003",
prompt: "test prompt",
temperature: 0.5,
max_tokens: 512,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
})
});
const data = await response.json();
return data.choices[0].text;
}
Thanks
I have tried consulting many websites to see solutions to this but have had no luck.
400 (Bad Request) error code typically means that client request's data is incorrect. So yes, must be something with your auth headers/body of request. Quite often response contains a reason, please try to print the text of response (before trying to get json output), e.g.
console.log(response.text());
or just check Network Tab in Dev Console
You are almost there, you just have the wrong endpoint. If you change that your code will work.
The correct endpoint:
https://api.openai.com/v1/completions
I tested it with your code and it worked. Here is your code rewritten with the correct endpoint.
async function getResponseFromAPI(message) {
const apiKey = "sk-myapikey";
const endpoint = `https://api.openai.com/v1/completions`;
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": `application/json`,
"Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: "text-davinci-003",
prompt: "test prompt",
temperature: 0.5,
max_tokens: 512,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
})
});
const data = await response.json();
return data.choices[0].text;
}
Source: https://platform.openai.com/docs/api-reference/completions/create

Getting bad request error when updating a number in MongoDB

I was trying to update a single element(which is a number) that is stored in mongodb.
here is the request I sent to the DB:
const handleDelivered = (num) =>{
const total = service.quantity;
const final = parseInt(total) + num;
console.log(total,final);
const url = `http://localhost:5000/services/${idOfService}`;
fetch(url,{
method :'PUT',
headers :{
'content-type': 'application/json',
},
body : JSON.stringify(final)
})
.then(res => res.json())
.then(product =>{
console.log(product);
})
}
The data stored inside MongoDB is an object of the array. to execute the operation I tried to build an API with express.
here is the code for the API
app.put('/services/:id', async(req,res)=>{
const id = req.params.id;
const filter = {_id : ObjectId(id)};
const options = { upsert: true };
const updatedData = req.body;
const updateDoc = {
$set: {
quantity : updatedData.quantity,
},
};
const result = await serviceCollection.updateOne(filter, updateDoc, options);
res.send(result);
});
Whenever I click on the button to update it shows an error saying:
PUT(link)400 (bad request)
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
This should work for you:
In you request body do this:
body : JSON.stringify({quantity: final})
Instead, send an object as a string whit:
res.send(result);
Send as a JSON like this:
res.status(200).json(result);
And to your client to catch better the error that your service throw add the closure catch to the fetch.

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;
}

SyntaxError: Unexpected token r in JSON at position 0 on reactjs login page

I have been trying to make a login page in reactjs but it's throwing me an error in console like
SyntaxError: Unexpected token r in JSON at position 0 but I got 200 status code in network tab and also I'm getting "redirect" in both response and preview tab under the network tab.
I tried the same code(except it was if(response.ok) this time) with another server of my friend and it successfully redirects it to another page
This is the code that I've been trying: is response.data not correct for reactjs?
performLogin = async () => {
var body = {
password: this.state.password,
email: this.state.email
};
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
};
const url = "/api/authenticate";
try {
const response = await fetch(url, options);
const result = await response.json();
console.log(response); //nothing is showing in console for this statement
if (response.data == "redirect") {
this.props.history.push(`/verifyOtp/${this.state.email}`);
} else {
console.log("login failed");
window.alert("login failed");
}
} catch (error) {
console.error(error);
}
};
edit: I also tried it in postman and it gives "redirect" as response in postman so the api must be working fine
Your problem is in this line
const result = await response.json();
Your response is ok, everything is ok, but when you try to do response.json() and the response from the request isn't a valid json (maybe just a normal text), it will give you that error.
Because response can be a text or a json, you need to do some checking. Where is how to check if response is a json
This is kind of bad because on every request you will need to do this type of checking (transform it to text, try to parse, bla bla...), so What I recommend it you to use something better than fetch.
Axios is very good because it already do that checking.
For your example:
performLogin = async () => {
var body = {
password: this.state.password,
email: this.state.email
};
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
};
const url = "/api/authenticate";
try {
const response = await fetch(url, options); // Fetch the resource
const text = await response.text(); // Parse it as text
const data = JSON.parse(text); // Try to parse it as json
// Do your JSON handling here
} catch(err) {
// This probably means your response is text, do you text handling here
}
}

Categories

Resources