i have a frontend where I define a string in this case videoLink.
Besides that I have an async function that starts when a button is clicked.
//sveltekit
async function addToQueue(){
console.log(videoLink);
const res = await fetch('/tool/server', {
method: 'POST',
body: {
videoData: videoLink
}
})
const json = await res.json()
console.log(json);
videoLink = "";
}
This function sends an http-post request with fetch to my server.js file.
/** #type {import('#sveltejs/kit').RequestHandler} */
export async function POST(event) {
const data = await event.request.body;
const link = data.videoData;
console.log(link)
}
when i run the post-request (by clicking the Button in my frontend), my server logs undefined. As far as I know the server gets the POST request, because it logs only if I click the button.
But why does it return undefined? I have tried to parse the json, but it didn't work. Can anyone help me? What is wrong with my JSON?
Open the developer tools in your browser. Look at the Network tab. Examine the Request payload you are sending:
[object Object]
fetch doesn't support plain objects for the body option. It will convert them to strings with their toString() method.
You need to either provide:
an object which fetch does support. The common options are
URLSearchParams for application/x-www-form-urlencoded data
FormData for multipart/form-data
an encoded string (such as the output of JSON.stringify) and also set the content-type HTTP request header to match
Which you choose will depend on what encodings the server side code supports.
So I have provided
headers: {
'Content-Type': 'application/json'
}
to fetch the data.
On the server side I've done the following:
export async function POST({request}) {
const data = await request.json()
console.log(data)
return {}
}
Now the function returns {}, which isn't mandatory. The reason it works now is that POST gets {request} as an argument.
Notice the curly braces. Thanks a lot to #Quentin for his help.
Related
I am trying to convert a javascript object array to JSON to pass it with the POST request to the cloud function. However when I use the JSON.parse() function I get an error:SyntaxError: Unexpected token u in JSON at position 0
Can someone tell me what I'm doing wrong, this is my POST request:
const body = `{
"item":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}]
}`;
const init = {
method: 'POST',
body
};
fetch('https://us-central1-web-app-bbo-prod.cloudfunctions.net/TestObject', init)
.then((response) => {
return response.json(); // or .text() or .blob() ...
})
.then((text) => {
// text is the response body
})
.catch((e) => {
// error in e.message
});
and this my cloud function:
exports.TestObject = functions.https.onRequest(async(request, response)=> {
var corsFn = cors();
corsFn(request, response, async function() {
const myJSON = request.body.item;
console.log(JSON.parse(myJSON))
//console.log(item)
})})
TLDR:
Server: remove JSON.parse
Client: change init to
const init = {
method:'POST',
body:JSON.stringify(body),
headers: {
'Content-Type':'application/json'
}
}
Explained:
You've got three issues I see.
Anytime you see the following you are calling JSON.parse on invalid stringified JSON.
SyntaxError: Unexpected token u in JSON at position 0
First, req.body should already be JSON if everything's working properly and you received JSON. To call JSON.parse(req.body.item) is to pass an Object to a function that takes strings. You can just refer to req.body.item.
Second you have to make sure you're sending the correct body, you are passing an object as the body for the fetch function. I'm not familiar with the fetch function but a quick look at the Mozilla examples indicate that should it should be stringified, i.e. body:JSON.stringify(body). The object you pass likely is either converted to form data or has toString() called on it and you're sending [object Object].
// REPL
> ({foo:'bar'}).toString()
'[object Object]'
Third, you have to make sure it gets parsed properly on the backend.
According to the GCloud nodeJS docs the nodejs google cloud functions implement an endpoint for an Express Router.
Normally if you wanted to use JSON the way you are you would need the body parser BodyParser middleware. The examples here (GCloud HTTP Functions) indicate that the body-parser middleware is already instead and working based off of Content-Type header.
Since it's deciding whether to parse it as JSON based on content type you want to set the header in your fetch function as 'content-type':'application/json'.
i've been trying to fetch some data from the riot's api, and I have a problem:
This is the important part of the code:
const getUsuario = async (name) => {
const resp = await fetch(`${APIRUL}${name}${apikey}`, {
method: 'GET',
mode: 'no-cors',
headers: {
"Content-Type": "application/json",
},
});
const { data } = await resp.json();
return data;
};
getUsuario("user-name");
If i put mode: cors. I have a problem with CORS, but if I have as the example above, it shows up this:
champions.js:15 Uncaught (in promise) SyntaxError: Unexpected end of input
at getUsuario (champions.js:15)
This is the line 15:
const { data } = await resp.json();
I found a similar error to what you are seeing here: fetch() unexpected end of input
Try printing the response before turning it to json and see if you see type opaque. This is specific to fetch requests made with mode no-cors. There seems to be a lot of restrictions to what you can do with this kind of response.
Updated: The RiotGames api server does not return the CORS headers for a reason. Most likely they don't want you to access their API directly from the browser. You need to have a backend make those api requests for you which can then forward the responses to your frontend.
So I am testing a cloudflare web worker script and i can't seem to get my code to work with POST requests and such.
url_without_query_strings = request.url.split('?')[0] //remove all query strings
const response = await fetch(url_without_query_strings, {
method: request.method,
headers: request.headers
})
return response
Can anyone see what I am doing wrong ?
The problem is that you are only copying method and headers from the request, but it has more properties than that. POST requests, for example, have a body property which your code is not copying.
In order to perform a fetch that inherits everything from the original request except the URL, do:
const response = await fetch(url_without_query_strings, request)
That is, pass the request itself as the second parameter, rather than a dict. This works because a request object has property names matching exactly all of the options that fetch()'s second parameter expects.
Note that, awkwardly, if you want to modify any request property other than the URL, but keep other properties the same, then you must pass the request as the first parameter and specify the modifications in the second parameter:
const response = await fetch(request, {headers: myHeaders})
This means that if you want to modify the URL and some other property, you need to perform two steps -- first created a new Request object that changes the URL, then modify the headers:
let request2 = new Request(newUrl, request)
const response = await fetch(request2, {headers: myHeaders})
Or, of course, you could do the opposite order:
let request2 = new Request(request, {headers: myHeaders})
const response = await fetch(newUrl, request2)
Or, alternatively, for the specific case of headers, you can take advantage of the fact that once you've constructed your own Request object, you're allowed to directly modify its headers:
let request2 = new Request(newUrl, request)
request2.headers.set("X-Foo", "Bar")
const response = await fetch(request2)
I want to update a document in Mongo, but when I send an Axios POST request to the server with params for the updates I receive nothing but a blank object on the server side - I'm using Node.js with an Express server (MERN stack).
I have tried the qs library module and Node's querystring module. I tried including headers with
'Content-Type': 'application/x-www-form-urlencoded' and 'application/json'.
My Axios POST request:
const A = 1;
const B = 2;
const data = { A, B };
console.log(qs.stringify(data)); // A=1&B=2
axios.post(url('upVote'), qs.stringify(data));
The server route:
app.post('/upVote', async (req, res) => {
console.log(req.params); // {}
await DB.updateVote(ID, collection, voteCount);
res.end();
});
The headers as shown by Chrome's DevTools.
... Also, all my axios.get() requests work fine and grab data from Mongo and send it back to my app properly, and the url/endpoints match.
There are a couple of ways to send data to the server with axios.
I see the confusion with the documentation in axios, I have not seen this usage before and it does seem to be broken upon looking at the request logs and object.
1) axios.post receives body of the request as a second parameter. So if you want to pass parameters to axios, you should do something like this:
const B = 2;
const data = { A: 1, B: 1 };
axios.post(url('upVote'), {}, { params: data });
Note that axios will handle stringification on it's own and that the third parameter is a config object.
On the server the params will be available at request.query
2) If you want to stringify the parameters yourself, then you should append them into your URL like so
axios.post(`url('upVote')?${qs.stringify(data)}`);
Same here, data on the server will be under request.query
3) It's generally better to use the body of the post request to transfer large data payloads for convenience. You should also consider what your caching strategies are and if they rely on request url without the consideration of request body it may be a concern.
axios.post(url('upVote'), data);
In this case data on the server will be under request.body
UPD: Originally forgot to mention that you will need a body-parser middleware to access request.body.
4) You can use axios without method shorthands which may be useful for some people
axios({
method: 'POST',
url: url('upVote'),
params: data
})
This is identical to the example in 1.
And all of them return a Promise which you can .then().catch() or await.
I think you want .body instead of .params.As you are sending data in body by post using axios. You are printing params which will print nothing for this url/api .
Try
console.log(req.body) // instead of req.params
If this did not work then please show us your react code.
Moreover
In react you have to add .then() after axios else it will say unhanded promise
To get params on server side you have to make some changes
In axios (react)
axios.post(url('upVote/param'), qs.stringify(data));
In server
app.post('/upVote/:params', async (req, res) => {
console.log(req.params)
.....
})
I think you are calling res.end(). I think it should be res.send(...)
This answer should help: https://stackoverflow.com/a/29555444/1971378
I am trying to send a new push subscription to my server but am encountering an error "Uncaught (in promise) SyntaxError: Unexpected end of JSON input" and the console says it's in my index page at line 1, which obviously is not the case.
The function where I suspect the problem occurring (because error is not thrown when I comment it out) is sendSubscriptionToBackEnd(subscription) which is called in the following:
function updateSubscriptionOnServer(subscription) {
const subscriptionJson = document.querySelector('.js-subscription-json');
const subscriptionDetails = document.querySelector('.js-subscription-details');
if (subscription) {
subscriptionJson.textContent = JSON.stringify(subscription);
sendSubscriptionToBackEnd(subscription);
subscriptionDetails.classList.remove('is-invisible');
} else {
subscriptionDetails.classList.add('is-invisible');
}
}
The function itself (which precedes the above function):
function sendSubscriptionToBackEnd(subscription) {
return fetch('/path/to/app/savesub.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(subscription)
})
.then(function(response) {
if (!response.ok) {
throw new Error('Bad status code from server.');
}
return response.json();
})
.then(function(responseData) {
if (!(responseData.data && responseData.data.success)) {
throw new Error('Bad response from server.');
}
});
}
I have tried replacing single quotes with double quotes in the fetch call but that yields the same results.
I know that the JSON should be populated because it prints to the screen in the updateSubscriptionOnServer() function with subscriptionJson.textContent = JSON.stringify(subscription);, and I used that output in the google codelab's example server to receive a push successfully.
EDIT: Here is the JSON as a string, but I don't see a mistake in syntax:
{"endpoint":"https://fcm.googleapis.com/fcm/send/dLmthm1wZuc:APA91bGULRezL7SzZKywF2wiS50hXNaLqjJxJ869y8wiWLA3Y_1pHqTI458VIhJZkyOsRMO2xBS77erpmKUp-Tg0sMkYHkuUJCI8wEid1jMESeO2ExjNhNC9OS1DQT2j05BaRgckFbCN","keys":{"p256dh":"BBz2c7S5uiKR-SE2fYJrjPaxuAiFiLogxsJbl8S1A_fQrOEH4_LQjp8qocIxOFEicpcf4PHZksAtA8zKJG9pMzs=","auth":"VOHh5P-1ZTupRXTMs4VhlQ=="}}
Any ideas??
This might be a problem with the endpoint not passing the appropriate parameters in the response's header.
In Chrome's console, inside the Network tab, check the headers sent by the endpoint and it should contain this:
Example of proper response to allow requests from localhost and cross domains requests
Ask the API developer to include this in the headers:
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
This happened to me also when I was running a server with Express.js and using Brave browser. In my case it was the CORs problem. I did the following and it solved the problem in my case:
(since this is an Express framework, I am using app.get)
-on the server side:
res.set({
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
});
-on client side I used Fetch to get data but disabled the CORS option
// mode: "no-cors" //disabled this in Fetch
That took care of my issues with fetching data with Express
This can be because you're not sending any JSON from the server
OR
This can be because you're sending invalid JSON.
Your code might look like
res.end();
One of the pitfalls is that returned data that is not a JSON but just a plain text payload regardless of headers set. I.e. sending out in Express via something like
res.send({a: "b"});
rather than
res.json({a: "b"});
would return this confusing error. Not easy to detect in network activity as it looks quite legit.
For someone looking here later. I received this error not because of my headers but because I was not recursively appending the response body to a string to JSON.parse later.
As per the MDN example (I've taken out some parts of their example not immediately relevant):
reader.read().then(function processText({ done, value }) {
if (done) {
console.log("Stream complete");
return;
}
result += chunk;
return reader.read().then(processText);
});
For my issue I had to
Use a named function (not an anonymous ()=>{}) inside the .then
Append the result together recursively.
Once done is true execute something else on the total appended result
Just in case this is helpful for you in the future and your issue is not header related, but related to the done value not being true with the initial JSON stream response.
I know this question has already been answered but just thought I add my thoughts.
This will happen when your response body is empty and response.json() is expecting a JSON string. Make sure that your API is returning a response body in JSON format if must be.