Handling XML response with Javascript - javascript

I'm making a request to an API for some information. I need to send some information in order to get the required information back. The response is in XML format. When I make the request I get the following error
Uncaught (in promise) TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.
If a GET request can't have a body how do I send the required information? Basically how do I get this to work?
Here is my code.
getResponse = () => {
const url = 'http://api.pixelz.com/REST.svc/Templates/';
// The data we are going to send in our request
let data = JSON.stringify({
"contactEmail": "myemail#gmail.com",
"contactAPIkey": "MY-API-KEY"
})
// The parameters we are gonna pass to the fetch function
let fetchData = {
method: 'GET',
body: data,
headers: new Headers()
}
fetch(url, fetchData)
.then(function(response) {
// Handle response you get from the server
response.text()
.then(data => console.log(data))
});
}

Indeed GET requests can't have a body, meaning you don't send data while you are getting. There can be two things going on here.
That specific endpoint is supposed to use another method like POST
The data you want to send actually needs to be passed as querystring parameter http://api.pixelz.com/REST.svc/Templates/?contactAPIkey=....&contactEmail=...

Related

How can I correctly fetch the Riot API with JS?

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.

Service worker fetch event for POST request get body

How can I capture the body of POST request in a Service Worker. I am sending authentication parameters in the POST request, so I want to intercept the fetch request in service worker and show results from IndexDB.
Following is the code from my service worker
self.addEventListener("fetch", event => {
let cloned = event.request.clone();
console.log(cloned.json()); //<<- This line returns error : TypeError: Failed to execute 'json' on 'Request': body stream is locked
let response = new Promise((resolve)=>{
let key='mykey'; //Genereate from body, so read body
let stored = localforage.getItem(key);
if(stored){
resolve(stored);
}else{
resolve(fetch(cloned).then(res => res.json()).then(res=>{
localforage.setItem(key,res);
}));
}
})
event.respondWith(response);
})
p.s : please ignore syntax errors if any.
Since request body is ReadableStream, for the reasons #Mr.Vibe mentions in the above comment it cannot be accesed through event.request.body, One way to access the body is by using await event.request.json(), However one should notice that once the request body is read it cannot be reused as body of a request as it throws an error like This ReadableStream is disturbed (has already been read from), and cannot be used as a body. So its better we clone the request and then access its body as in await event.request.clone().json(), So that later on we could use the original request unharmed.
self.addEventListener("fetch", async (event) => {
let clonedBody = await event.request.clone().json();
...
})

Error: SyntaxError: Unexpected end of JSON input at fetch.then.response

I get this error every time I try to use the POST method in my API.
SyntaxError: Unexpected end of JSON input at fetch.then.response
When I use the GET method I get the data normally.
This is the code:
const teste = () => {
fetch("myURL/test", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
id: 1,
name: "Teste",
amount: 1,
value: 3
})
})
.then(response => response.json()) //Here is the error
.then(data => {
console.log(data);
})
.catch((err)=>console.log(err))}
Can someone help me? Thank you.
EDIT:
I just add this line to see the log:
.then(response => console.log(response))
Here is what I got:
Response {
type: "cors",
url: "myURL/test",
redirected: false,
status: 201,
ok: true,
…}
body: (...)
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 201
statusText: ""
type: "cors"
: "myURL/test"
__proto__: Response
It means that the page fetched at myURL/test does not responds with JSON content, or with malformed JSON content. This is not an error in your script, which is fine, this is an error with your server, that is not serving JSON content at myURL/test.
Also, note that servers might not respond similarly to GET requests and POST request for the same URL! If you fetch valid JSON from a GET request but, as you described, failed to fetch valid JSON from a POST request, your server might be serving different content depending on the request type. Investigate that.
Debug tips
Replace then(resp => resp.json()) by then(resp => resp.text()).then(console.log) to see what the served content looks like
Use Postman to simulate API calls, and see what the served content looks like, with more details
Examine the response with the developer tools:
In Chrome
Open the console (F12)
Go to the network tab
Click on the file server by myURL/test
Click on response: that will be the text content. It shoud be properly formatted JSON.
Basically GET method does not send your body object to the server in which you get the response. Only the POST action will send your body object to the server.
I assume that the object you wish to send is the problem. Either the server which you are trying to connect does not expects the body object as string or you should make sure you have parsed the JSON properly before processing.
Looks like the API you're calling, doesn't have a response body on this particular POST. Then when you call response.json() (converting response.body to json) it runs into error.
Or maybe the response is body is not a valid json body.
If you wanna handle this error more fashion way you could go like this:
tryGetJson = async (resp) => {
return new Promise((resolve) => {
if (resp) {
resp.json().then(json => resolve(json)).catch(() => resolve(null))
} else {
resolve(null)
}
})
}
https://github.com/github/fetch/issues/268#issuecomment-399497478
(for people coming later but dealing with this problem)
The problem is most probably server error or invalid URL but you can't see it because all examples on internet how to work with fetch are missing one important part - the server or network failure.
I think the correct way how to deal with fetch is test response if contains errors before conversion to json.
Check the part of the first then in example where it.ok is tested:
async function fetchData() {
return await fetch('https://your-server.com/some-NOt-existing-url/')
.then(it => {
if (!it.ok) {
throw `Server error: [${it.status}] [${it.statusText}] [${it.url}]`;
}
return it.json();
})
.then(receivedJson => {
// your code with json here...
})
.catch(err => {
console.debug("Error in fetch", err);
setErrors(err)
});
}
(note: it is just name convention borrowed from Kotlin, it makes JavaScript code shorter. It is alias for anything on left side of expression so in this case for response)

Javascript Cloudflare worker script not allowing post requests

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)

Uncaught (in promise) SyntaxError: Unexpected end of JSON input

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.

Categories