Can't use response.json() on received user object from MS Graph - javascript

I'm trying to get a user from the MS Graph API.
export const getUser = async (id) => {
//Gives me the token
const token = await getToken(["User.Read", "User.ReadWrite"])
//Appends to headers
const headers = getHeaders(token)
const options = {
method: "GET",
headers: headers
};
return fetch(`https://graph.microsoft.com/v1.0/users/${id}`, options)
}
getUser("MYID").then(response => response.json()).then(response => {
debugger
}).catch((error) => {
debugger
})
Normally I can use .json() to resolve promises from MS Graph, but this call fails with the following error:
Unexpected token < in JSON at position 0
If I remove .json() I can read the response, which gives me the following:
response: Response
body: ReadableStream
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "basic"
Given the fact that the body object should be of type ReadableStream, my intuition tells me that I in fact should be able to resolve the promise with .json(), i.e. response.body.json(). However, when I try to do so, I get the following error:
TypeError: response.body.json is not a function at http://localhost:3000/static/js/main.chunk.js:4679:40
I'm pretty unsure what's going on, and naturally I would love if you guys could give me some insights on what's going on. All my other graph "GET" calls encounter no problem when I want to resolve the readableStream.

I believe you are getting response body as html or xml which is why .json() which is used to parse the data to json is throwing exception Unexpected token < in JSON at position 0

Related

React JS: Unexpected token < in JSON at position 0

I'm trying to parse and get fetch data from URL, but got the error like:
Unexpected token < in JSON at position 0
the URL contains this such of data:
<wfs:FeatureCollection xmlns="http://www.opengis.net/wfs" xmlns:wfs="http://www.opengis.net/wfs" xmlns:gml="http://www.opengis.net/gml" xmlns:kict="kict" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://192.168.0.70:28080/geoserver/schemas/wfs/1.0.0/WFS-basic.xsd kict http://192.168.0.70:28080/geoserver/wfs?service=WFS&version=1.0.0&request=DescribeFeatureType&typeName=kict%3Av_plans_photo">
<gml:boundedBy>
<gml:null>unknown</gml:null>
</gml:boundedBy>
<gml:featureMember>
<kict:v_plans_photo fid="v_plans_photo.fid-400b9b06_17e425c6260_-1a99">
<kict:rownum>61689</kict:rownum>
<kict:plan_id>6178a7a0974e58001ac90ac5</kict:plan_id>
<kict:cmo>5c38212c23b65b0d045d2de8</kict:cmo>
<kict:cmo_str>5c38212c23b65b0d045d2de8</kict:cmo_str>
<kict:plan_name/>
<kict:plan_cn>포트홀 작업추가</kict:plan_cn>
<kict:opert_ty>B1</kict:opert_ty>
<kict:operTy>B1</kict:operTy>
<kict:opert_sttus>A4</kict:opert_sttus>
<kict:opert_plan_cn>포트홀 작업추가</kict:opert_plan_cn>
<kict:create_at_year>2021</kict:create_at_year>
<kict:create_at_month>10</kict:create_at_month>
<kict:create_at_week>43.0</kict:create_at_week>
<kict:created_at>2021-10-27T01:13:04.557Z</kict:created_at>
<kict:created_by>강릉_보수원002</kict:created_by>
<kict:cvpl_ty>5cfda3bab615b60845c79dda</kict:cvpl_ty>
<kict:acmslts_id>6178a89e974e58001ac90b02</kict:acmslts_id>
<kict:cvpl_ty_code>900900</kict:cvpl_ty_code>
<kict:cvpl_ty_nm>포트홀</kict:cvpl_ty_nm>
<kict:cvpl_name>포트홀</kict:cvpl_name>
<kict:cmo_org_code>1613208</kict:cmo_org_code>
<kict:cmo_grp_nm>원주청</kict:cmo_grp_nm>
<kict:cmo_code>22</kict:cmo_code>
<kict:cmo_nm>강릉국토관리사무소</kict:cmo_nm>
<kict:cmoNm>강릉국토관리사무소</kict:cmoNm>
<kict:photo_type>완료</kict:photo_type>
<kict:begin_lat>37.7164584026444</kict:begin_lat>
<kict:begin_lon>128.987696737366</kict:begin_lon>
<kict:photo_lat>37.7161098</kict:photo_lat>
<kict:photo_lon>128.9880585</kict:photo_lon>
<kict:geom>
<gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
<gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">128.9880585,37.7161098</gml:coordinates>
</gml:Point>
</kict:geom>
<kict:photo_url>http://hms.molit.go.kr:9080/api/uploads/2021/6178a7a0974e58001ac90ac5_202110271017147661635297434478.png</kict:photo_url>
<kict:store_path>uploads/2021/6178a7a0974e58001ac90ac5_202110271017147661635297434478.png</kict:store_path>
<kict:photo_filename>6178a7a0974e58001ac90ac5_202110271017147661635297434478.png</kict:photo_filename>
<kict:photo_size>1122621</kict:photo_size>
</kict:v_plans_photo>
</gml:featureMember>
</wfs:FeatureCollection>
I just used fetch to parse and fetch data like below:
let url = "/geoserver/wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=kict:v_plans_photo&srsName=EPSG:4326&maxFeatures=10000&format_options=callback:getJson&cql_filter=INTERSECTS(geom, POINT (128.9880585 37.7161098))"
if (url) {
fetch(url, {
headers : {
'Accept': 'application/json'
}
})
.then(response => response.json())
.then((response) => {
console.log(response)
},
(error) => {
this.setState({
isLoaded: true,
error
});
console.log(`fetch failed: ${this.state.error}`)
}
)
}
How can I get data from that URL using fetch?
It is throwing such error because you are trying to parse a non-json datatype.
Response data is actually an XML. You have to first parse the text and then parse the XML.
Refer this - https://codetogo.io/how-to-fetch-xml-in-javascript/
Visit this page for detailed info
The json() method of the Response interface takes a Response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON.
Note that despite the method being named json(), the result is not JSON but is instead the result of taking JSON as input and parsing it to produce a JavaScript object.
As you can see, the json() takes JSON format as input and then parses it, as your data is not in a JSON format you are bound to get the following error
Unexpected token < in JSON at position 0
Your result is in XML format. Try the following
let url = "/geoserver/wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=kict:v_plans_photo&srsName=EPSG:4326&maxFeatures=10000&format_options=callback:getJson&cql_filter=INTERSECTS(geom, POINT (128.9880585 37.7161098))"
if (url) {
fetch(url, {
headers : {
'Accept': 'application/json'
}
})
.then(response => response.text())
.then(response => {
const parser = new DOMParser();
const xml = parser.parseFromString(data, "application/xml");
console.log(xml);
},
(error) => {
this.setState({
isLoaded: true,
error
});
console.log(`fetch failed: ${this.state.error}`)
}
)
}

How to parse POST array data in AWS Lambda

I'm trying to send JSON data with an array to an AWS Lambda function, but I can't parse the array.
In the frontend I'm requesting this way:
const ids = ['long_id1', 'long_id2', 'long_id3'];
const request = await fetch(
'https://ID.execute-api.us-east-1.amazonaws.com/default/endpoint',
{
headers: {
"accept": "application/json, text/plain, */*",
"content-type": "application/json",
},
body: JSON.stringify({
userIds: ids
}),
method: 'POST'
}
)
const response = JSON.parse(await request.text());
In the lambda I have the following code:
exports.handler = async (event) => {
const parsed = JSON.parse(event); //also tried: JSON.parse(JSON.stringify(event)) because I saw someone recommending it
return {
statusCode: 200,
body: JSON.stringify(parsed)
}
}
But I get event.body as a string. For example if I log the event variable I get:
event: {
...,
body: "{\"userIds\":[\"long_id1\",\"long_id2\",\"long_id3\"]}"
}
But, if I try to parse the body, it throws this error:
ERROR SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse (<anonymous>)
at Runtime.exports.handler (/var/task/index.js:11:23)
at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)
2021-08-08T07:43:05.425Z 5feeddb7-6254-405d-b311-42924abc5f4d ERROR SyntaxError: Unexpected token u in JSON at position 0 at JSON.parse (<anonymous>) at Runtime.exports.handler (/var/task/index.js:11:23) at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)
Any idea what am I doing wrong?
Update
Not sure if was some kind of typo but now I'm able to get the data properly. I'm just doing what #Mark B said with the following code in the lambda function:
exports.handler = async (event) => {
const { userIds } = JSON.parse(event.body);
const result = await doSomethingWithUserIds(userIds)
return {
statusCode: 200,
body: JSON.stringify(result)
}
}
Thanks for all the help :)
event is an object. You don't need to parse that into JSON, it's already a JSON object. event.body is a string. You need to parse that property of the event object into JSON.
JSON.parse(event.body)
Not sure if was some kind of typo but now I'm able to get the data properly. I'm just doing what #Mark B said with the following code in the lambda function:
exports.handler = async (event) => {
const { userIds } = JSON.parse(event.body);
const result = await doSomethingWithUserIds(userIds)
return {
statusCode: 200,
body: JSON.stringify(result)
}
}
Thanks for all the help :)

javascript fetch() works with breakpoints, but fails with TypeError when run normally

I'm trying to fetch() text/plain data from a remote service. If I place a breakpoint in the promise "then" chain, the text data from the server is available. Without the breakpoint, I get a fetch() exception.
I am using a prototype design pattern (see below). When I place a breakpoint in the "then" chain as shown below, the data from the remote service is successfully retrieved. Without the breakpoint, the catch() is executed and the error is:
TypeError: Failed to fetch
I'm totally stumped and would appreciate any help!
Note, the server (a python app) sends back html, with
self.send_header("Access-Control-Allow-Origin", "*")
Also, if I use Ajax (FWIW, it works). I'd like to get it working with fetch() however.
function Fetch(Msg) {
// Msg contains some info on how to construct the JSON message to transmit -- not relevant here.
this.help = `
The Fetch object specifies communication basics using
the fetch(...) mechanism.
`;
// some misc object vars...
}
Fetch.prototype = {
constructor: Fetch,
postData: async function (url = '', data = {}) {
const response = await fetch(url, {
method: 'POST,
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'text/plain',
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
// body data type must match "Content-Type" header
body: JSON.stringify(data)
});
return await response.text(); //
},
handleErrorsInResponse: function (response) {
var debug = new Debug("Fetch.handleErrorsInResponse");
debug.entering();
debug.leaving();
},
handleReponse: function (response) {
var debug = new Debug("Fetch.handleResponse");
debug.entering();
console.log(response);
debug.leaving();
},
handleErrorsInFetch: function (response) {
var debug = new Debug("Fetch.handleErrorsInFetch");
debug.entering();
console.log(response);
debug.leaving();
},
call: function (payload) {
this.postData(
'http://some.url/',
payload)
.then(this.handleErrorsInResponse) // If I place a breakpoint here it works!
.then(this.handleReponse)
.catch(this.handleErrorsInFetch);
},
}
// Ultimately called by something like
comms = new Fetch();
someData = {"key": someJSON};
comms.call(someData);
Remove the wait on the response.
Replace
return await response.text();
by
return response.text();

Using the fetch API to query an endpoint to get a json response and getting back an empty response error

Please forgive the long debug info and code. I figure its all relevant.
Im trying to query an api endpoint to get a ticket back. I query using postman and get the ticket response back as text that is shown in the headers tab. However, I want to use java script to get that ticket back and do other stuff with it. When i run the script, it logs an error to the console:
SyntaxError: Unexpected end of input
at FetchDemo.html:48
(anonymous) # FetchDemo.html:54
Promise.catch (async)
getTicket # FetchDemo.html:53
the response i get is this:
type: "opaque"
url: ""
redirected: false
status: 0
ok: false
statusText: ""
headers: Headers {}
body: (...)
bodyUsed: false
__proto__: Response
My code is below:
<script>
let URL = 'https://jsonplaceholder.typicode.com/posts/';
let TabURL = 'http://15.222.0.10/trusted/?username=admin';
document.getElementById("getTicket").addEventListener('click',getTicket);
function getTicket() {
console.log("in side getTicket");
//setup an options array to pass into the fetch call
let options = {
method: 'POST',
mode: 'no-cors',
headers: {
'Accept' : 'application-json,*/*',
'Content-Type' : 'application:json'
}
};
console.log(TabURL);
console.log(options);
fetch (TabURL,options)
.then(response => {
console.log(response);
return response.json();
})
.then(response => {
console.log(response);
})
.catch(error => {
console.error(error);
});
}
</script>
From the specs:
An opaque filtered response is a filtered response whose type is "opaque", URL list is the empty list, status is 0, status message is the empty byte sequence, header list is empty, and body is null.
The reason you're getting an opaque response, is because you use the no-cors flag. If you want to do cross-domain requests such as these, you need CORS.
https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
https://developer.mozilla.org/en-US/docs/Web/API/Response/type

How can I log in to an API and catch login errors using fetch on React Native?

I'm making an application that requires login to an API. I have a login form which sends the ID number and password to the API, and the API should respond like this:
[
{
"user_id":"032984",
"user_number":"140521351",
"token":"990nZtMtEUUMY"
}
]
If there is a login error, the API responds with:
[
{
"ERROR": "INVALID PASSWORD | NOT FOUND 1SELECT user_id, lastname, password, user_number FROM user where user_number = 'INVALIDVALUE'",
},
]
I want to be able to catch a login error with an if statement, like if there is the ERROR object in this JSON, display an alert, else login and save the user_id and token to variables I can use in different screens of the app to send more requests to the API, get those responses in JSON, and show the data I need.
How can I make this happen?
So far, here's the code for my login function:
// login function
_userLogin = () => {
this.setState({ isLoggingIn: true, message: '' });
// send request to API properly
fetch("https://api.company.com/v4/users/json.php", {
method: "POST",
// our headers
headers: {
'Content-Type': 'application/json',
'Connection': 'close',
'Accept': '*/*',
'User-Agent': 'InternalApp/0.1 (InternalApp; ReactNative) Expo/33',
'Accept-Language': 'en-US;q=1.0',
'Accept-Encoding': 'gzip, deflate'
},
// body of the request with number/password
body: JSON.stringify({
user_number: this.state.number,
password: this.state.password,
}),
})
.then(response => {
return response.json(); // make it json?!
}).then(responseData => {
// debug messages
console.log(responseData);
console.log("Moving on to parsing JSON"); // CODE WORKS TO HERE
// parse json
var jsonObj = JSON.parse(responseData); // CODE STUCK HERE
// debug messages
console.log("JSON parsed");
if (jsonObj.ERROR)
console.log("Error caught");
else
this.setState(prevState => ({
credentialJson: prevState.credentialJson = responseData,
isLoggingIn: false,
}))
this.props.onLoginPress();
})
};
I'm really new to React Native and StackOverflow, please excuse any formatting issues with the question. I hope I've provided enough detail.
Based on your comments to this answer and the output of console.log(responseData) your responseData is an Array and your data is an Object inside the first array element. Access your data through responseData[0]. For example:
responseData[0].token
//Should return "990nZtMtEUUMY"
Here is how you would check if there is an error set:
if(responseData[0].ERROR){}
Your fetch library fetch returns a Promise so if the API actually throws an error you can add a catch statement.
fetch(url).then().catch((error) => {
console.log("Error", error);
});
The other thing is the reason your code is halting at JSON.parse is that you already parsed the json in a previous .then clause (response.json()) so your trying to parse an object, not a string, which JSON.parse expects.

Categories

Resources