JavaScript - Cannot GET /api/list - javascript

I am working on a website where a user should be able to post items to a list. Right now, when I try posting something it comes up with an error saying
Failed to load resource: the server responded with a status of 422 (Unprocessable Entity).
When clicking on it in the console it opens a new tap where it just says
Cannot GET /api/list
Also in the command prompt, it says
Unhandled rejection Error: Can't set headers after they are sent.
Does anybody know why this might be and what I can do to fix it? Here are some snippets of my code:
Index.HTML:
fetch('/api/list', options)
.then(response => response.json())
.then(response => {
if (response.status == 'OK') {
console.log('song is added')
getList(items)
} else {
alert(response.message)
}
})
}
Server.js:
app.post('/api/list', userIsAuthenticated, (req, res) => {
let {
titleArtist
} = req.body
let user_id = req.session.user.id
// seaching for user id in database
let query = {
where: {
userId: user_id
}
}
It might also be somewhere else in the code it goes wrong. Let me know if I should post more snippets of code.

This is because you are making a GET request to POST API.
This is how you can make POST request
fetch(url, {
method: 'POST', // or 'PUT'
body: JSON.stringify(data), // data can be `string` or {object}!
headers:{
'Content-Type': 'application/json'
}
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));

Related

Localhost Fetch request failing

I have a flask api (running on host='0.0.0.0', port=8080, which should cause it to run on my priv ip), and a javascript fetch request, which when called isnt able to reach the api for some reason. The javascript is running in a webpage hosted on http://127.0.0.1:5500. Yes I have tried curl and it works perfectly. The code for the fetch request is
const lbutton = document.getElementById("lbutton");
lbutton.addEventListener("click", function() {
console.log('button clicked');
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
fetch('http://not gonna give out my ip:8080/api/log', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({email: email, password: password})
})
.then(response => {
console.log('Success:', response);
if (response.ok) {
console.log('worked');
} else {
throw new Error('Server response was not OK');
}
})
.catch(error => {
console.error('Error:', error);
});
});
Can someone explain to me why it is not working, I have been trying to figure out how to do this for ages.
I tried to make it send a POST request to my api, which should work and the api should receive login info, but the request is not making it through at all.
The fetch api is making a GET request to http://127.0.0.1:5500/login.html?email=test#gmail.com&password=test

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());

Firebase 'Unhandled Rejection' and 'Can't set headers after they are set' JavaScript error

Firstly, please note that I am very very new to JS and coding as a general :)
Desired behaviour:
I have written the following JS HTTPS Firebase function which, which takes in a query parameter locationId, it performs a GET API call and saves the response back to Firebase. The code correctly saves the data to Firebase as desired. I have come across similar issues but i'm struggling to adapt those solutions to my specific issue below. From what I see, I'm only sending the response once.
Specific error: The following is the console output
Cannot set headers after they are sent to the client
Unhandled rejection
My function:
exports.doshiiGetMenuForOnboardedVenue = functions.https.onRequest((req, res) => {
// Forbidding PUT requests.
if (req.method === 'PUT') {
return res.status(403).send('Forbidden!');
}
cors(req, res, () => {
const locationId = req.query.locationId;
console.log('locationId', locationId);
if (locationId){
console.log('locationId', locationId);
var token = jwttoken();
const options = {
headers: {
'content-type': 'application/json',
'authorization': 'Bearer ' + token}
};
const uri = 'https://sandbox.doshii.co/partner/v3/locations/' + locationId + '/menu?lastVersion=:lastVersion&filtered=true'
axios.get(uri, options)
.then(response => {
return admin.database().ref(`/venue-menus/${locationId}/`).set(response.data)
.then(response => {
return res.status(200).send(locationId)
})
.catch(err => {
return res.status(500).send({error: err})
})
})
.then(response => {
return res.status(200).send(locationId)
})
.catch(err => {
return res.status(500).send({error: err})
})//end axios
} else {
return res.status(500).send({error: 'locationId missing'})
}//end if-else (!locationId)
})//end cors
});
By flattening out your nested promises, you can see that your code is performing the following instructions (when the axios call doesn't throw an error):
admin.database().ref(`/venue-menus/${locationId}/`).set(response.data))
.then(response => res.status(200).send(locationId))
.catch(err => res.status(500).send({error: err})
.then(response => res.status(200).send(locationId)) // this line is always called after either of the above.
.catch(err => res.status(500).send({error: err})
As general practice, unless required, you should not nest promises with their own then() and catch() handlers as it will lead to bizarre effects like this.
Furthermore, if your code calls for using //end axios or //end cors messages, you should flatten out your code so it makes sense without those messages.
Adapting your code to "fail fast", correcting your API responses and appropriately hiding error stack traces gives:
const cors = require('cors')({
origin: true,
methods: ["GET"]
});
exports.doshiiGetMenuForOnboardedVenue = functions.https.onRequest((req, res) => {
cors(req, res, (err) => { // note: cors will handle OPTIONS method
if (err) {
// note: log full error at ERROR message level
console.error('Internal CORS error:', err);
// note: return only generic status message to client
return res.status(500).json({error: 'Internal Server Error'});
}
// Forbidding anything but GET requests.
if (req.method !== 'GET') {
// 405 METHOD_NOT_ALLOWED
return res.status(405)
.set('Allow', 'GET')
.json({error: 'Not Allowed!'});
}
const locationId = req.query.locationId;
console.log('locationId', locationId);
if (!locationId) {
// 400 BAD_REQUEST
return res.status(400).json({error: 'locationId missing'})
}
var token = jwttoken();
const options = {
headers: {
'content-type': 'application/json',
'authorization': 'Bearer ' + token
}
};
// note: Don't forget to enable billing for third-party APIs!
const uri = 'https://sandbox.doshii.co/partner/v3/locations/' + locationId + '/menu?lastVersion=:lastVersion&filtered=true'
axios.get(uri, options)
.then(response => admin.database().ref(`/venue-menus/${locationId}/`).set(response.data))
.then(() => {
// note: as locationId was already sent by the client, send new/useful
// information back or nothing but the right status code
res.status(200).json({ ref: `/venue-menus/${locationId}/` });
})
.catch(err => {
// note: log full error at ERROR message level
console.error('Failed to retrieve/save API data:', err);
// note: return only message to client
res.status(500).json({error: err.message || 'Internal Server Error'});
});
});
});

React Native network error in POST request when adding a body

it's me again.
I'm learning react native, for now im trying to upload a file, the api is already tested using postman and it does work so I wrote this code:
import * as DocumentPicker from 'expo-document-picker';
async login () {
let response = await DocumentPicker.getDocumentAsync({type: '*/*'})
const data = new FormData();
data.append('file', response)
// Fetch attempt ----------------------------------------
fetch("http://192.168.0.3:8000/api/file", {
method: "POST",
headers:{
"Content-Type": "application/x-www-form-urlencoded",
},
body: data
})
.then(response => response.json())
.then(response => {
console.log("upload succes", response);
})
.catch(error => {
console.log("upload error", error, JSON.stringify(error));
});
// Axios attempt ----------------------------------------
axios.post('http://192.168.0.3:8000/api/file', data, { headers:{ "Content-Type": "application/x-www-form-urlencoded"} } )
.then(res => {
console.log("goddaamittt wooork", res)
})
.catch(error => {
console.log("error", error, JSON.stringify(error))
});
}
When I remove the body and headers from that request it actually returns what the api should return when you try to POST to it without a 'file', some message "{'fileName': 'A file is required'}" but adding it to it I get a network error, the error I get when using fetch it:
upload error [TypeError: Network request failed] {"line":24646,"column":31,"sourceURL":"http://127.0.0.1:19001/node_modules/expo/AppEntry.bundle?platform=android&dev=true&minify=false&hot=false"}
when it reaches the axios attempt it says something like this:
[Unhandled promise rejection: TypeError: Network request failed]
I tried everything I knew, I need some help!
Idk if it is important but here is what DocumentPicker returns when I pick a file:
Object {
"name": "FB_IMG_1573232116651.jpg",
"size": 32482,
"type": "success",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fjsonplaceholder-bcb4c1c6-b37d-4634-99a5-3410d9b8654e/DocumentPicker/db8d78dd-2587-40e4-aed9-656c36df29f4.jpg",
}
This is the error I get when I remove the body from the axios request
error [Error: Request failed with status code 400] {"config":{"transformRequest":{},"transformResponse":{},"headers":{"Accept":"application/json, text/plain, /"},"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"method":"post","url":"http://192.168.0.3:8000/api/file"},"response":{"data":{"message":"File is required"},"status":400,"headers":{"map":{"cache-control":"public, max-age=0","x-robots-tag":"noindex","x-debug-token-link":"http://192.168.0.3:8000/_profiler/54e68c","x-debug-token":"54e68c","link":"http://192.168.0.3:8000/api/docs.jsonld; rel=\"http://www.w3.org/ns/hydra/core#apiDocumentation\"","content-type":"application/json","x-powered-by":"PHP/7.2.4","connection":"close","date":"Fri, 08 Nov 2019 17:54:12 GMT","host":"192.168.0.3:8000"}},"config":{"transformRequest":{},"transformResponse":{},"headers":{"Accept":"application/json, text/plain, /"},"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"method":"post","url":"http://192.168.0.3:8000/api/file"},"request":{"url":"http://192.168.0.3:8000/api/file","credentials":"omit","headers":{"map":{"accept":"application/json, text/plain, /"}},"method":"POST","mode":null,"referrer":null,"_bodyText":""}},"line":178773,"column":26,"sourceURL":"http://127.0.0.1:19001/node_modules/expo/AppEntry.bundle?platform=android&dev=true&minify=false&hot=false"}
It was such a dump solution, it took me hours to find this:
When I get the file from DocumentPicker I had to add the type of the file because DocumentPicker return an odd type called "success", when I changed it to 'image/jpeg' it worked :D its not a solution at all because I will need to find a way to know what type of file is each file a user chooses, anyways, this code works c:
let response = await DocumentPicker.getDocumentAsync({type: 'image/jpeg'})
response.type = 'image/jpeg' // <- lasdfkasdfaslfkfsdkdsaf
const data = new FormData();
data.append('file', response);
axios.post('http://192.168.0.3:8000/api/file', data , {headers: { 'Content-type': 'application/x-www-form-urlencoded' }} )
.then(res => {
console.log("gooosh", res.data)
})
.catch(error => {
console.log("error", error, JSON.stringify(error))
});
you should try to modify the content-type to
fetch("http://192.168.0.3:8000/api/file", {
method: "POST",
headers:{
'Content-Type': 'multipart/form-data',
},
body: data
})
and for the form-url-urlencoded, the fetch is not supported. you have to push it by yourself.you can see this answer.

Get Token From Api Dynamically To Access Content

I need to have the token to access the content like the announcement in my code. But what i do is to copy the token generated from loginUser() and paste it inside the getAnnouncement() under the fetch. I wrote Authorization : 'Bearer esuigiugeguigiguigi' <--- this is the token. The problem with this is that i need to copy and paste again the token every time it expires.
function loginUser(){
fetch('http://sample_website.com/api/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: document.getElementById("email").value,
password: document.getElementById("password").value
})
})
.then(data => data.json() )
.then(data => {
if(data.response){
redirect: window.location.replace("../Sample/Home.html")
} else{
alert("Invalid Email or Password");
}
})
.catch((err) => {
console.error(err);
})
}
function getAnnouncement(){
fetch('http://sample_website.com/api/announcements', {
method: 'GET',
headers: {'Content-Type': 'application/json',
Authorization : 'Bearer esuigiugeguigiguigi'},
})
.then(data => data.json())
.then(data => { console.log(data)
const output = document.getElementById("display");
output.innerHTML = `<ul>
<li><h2>${data.data.data[0].title}</h2></li>
<li>${data.data.data[0].body}</li>
<li>Created: ${data.data.data[0].created_at}</li>
</ul>`;
})
.catch((err) => {
console.error(err);
})
}
Usually the response from an API call to get the token will hold:
the token
the duration of the toke
a link to refresh the token
One basic way of dealing with this is to keep the token data in localStorage or in memory or something (you can decide for yourself), and then just use it on any request that needs authorization.
It is possible that the API in question gives a specific error in case a token has expired. You can then catch it, use the link to refresh the token to get a new one, and repeat the request.
As there is not much info about the API in hand, or what you're doing and what (if any) framework you are using, this it the best answer I can provide at the moment. There are a lot of libraries out there handling this stuff already, so you might want to look into existing solutions as well.

Categories

Resources