Reputation: 1
first post on this account, how exciting. Sadly, the contents are less exciting. I have found a very simple bug in the reader.json
function getResponseData
.
I want to have proper error handling in my application should, unexpectedly, the server I'm querying not provide me with valid JSON. The reader has an exception event for exactly this problem. However, reader.json
sets responseType
on the XHR to "json"
.
And as detailed here, this results in a null
value in response.response
on the XHR:
When setting responseType to a particular value, the author should make sure that the server is actually sending a response compatible with that format. If the server returns data that is not compatible with the responseType that was set, the value of response will be null.
getResponseData
wants to avoid work, and so will return responseJson
, if this is an object:
if (typeof response.responseJson === 'object') {
return response.responseJson;
}
However, in the version of Chrome I'm using typeof null
evaluates to "object"
.
I fixed this in my application by overriding the function and replacing the first line above with if (Ext.isObject(response.responseJson)) {
, but I think this should be fixed in the framework code.
I'm not really looking for an answer, but some kind of reaction for sencha would be nice.
This is posted here, because I skimmed over https://stackoverflow.blog/2019/10/30/why-sencha-is-moving-its-support-forums-to-stack-overflow/
Version information
EDIT: It appears my text was not explicit enough about my problem, so I'll add an example here. I have a store that looks similar to this:
Ext.define('myCoolStore', {
extend: 'Ext.data.Store',
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.Object.merge({
proxy: {
type: 'ajax',
withCredentials: true,
reader: {
type: 'json',
rootProperty: 'results'
},
listeners: {
exception: {
fn: me.onAjaxException,
scope: me
}
}
}
}, cfg)]);
},
onAjaxException: function(proxy, response, operation, eOpts) {
// ..
}
});
Now, if I do myCoolStore.load()
, I expect a server response like this:
{
"success": true,
"deprecated": false,
"results": [{
"id": "11730",
"bericht_id": "167",
"projekt_id": "1429",
"lastedit": "2021-08-10 16:01:20",
"lastedit_mitarbeiter_id": "182"
}],
"errors": [],
"messages": [],
"total": 1,
"metaData": null
}
However, the server might be bugged and return something else, that is invalid JSON. For the sake of simplicity, let's say someone forgot to turn of display_errors in his PHP ini, and the answer looks like this
[..date..] [php7:notice] [pid ..pid..] [client ..ip..] PHP Notice: Trying to get property 'myCoolProperty' of non-object in file.class.php on line 80, referer: ..myCoolSite..
{
"success": true,
"deprecated": false,
"results": [{
"id": "11730",
"bericht_id": "167",
"projekt_id": "1429",
"lastedit": "2021-08-10 16:01:20",
"lastedit_mitarbeiter_id": "182"
}],
"errors": [],
"messages": [],
"total": 1,
"metaData": null
}
The default behaviour of the reader.json
will not set an exception here, because the XHR will not be able to parse this, resulting in reponseJson
being null
, which will pass the typeof
-check.
Upvotes: 0
Views: 399
Reputation: 9734
According to RFC7159 specification, null
is a valid JSON value:
A JSON value MUST be an object, array, number, or string, or one of the following three literal names:
false null true
So I think this is the intended behaviour and not a bug. If you want to customize how responses are handled you can try one of the following two methods.
1. Define a global request exception handler
Do something like this in your Application.js
:
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
name: 'MyApp',
launch: function () {
const me = this;
Ext.Ajax.on('requestexception', me.onRequestException);
},
onRequestException: function (conn, response, options, eOpts) {
// this will run on every error during request (timeout, abort, 4xx, 5xx etc.)
// for example Ext.isEmpty(response.responseJson) will result true on null value
// add a breakpoint here and look what is in the variables in your case
}
});
2. Create a custom reader to intercept how response is converted
Define the reader something like this:
Ext.define('MyApp.data.reader.RestJson', {
extend: 'Ext.data.reader.Json',
alias: 'reader.myreader',
getResponseData: function (response) {
// evalutate here with debugger what you have in
// response and do the conversion you'd like
return something;
}
});
And use this reader whenever you need:
Ext.create('Ext.data.Store', {
model: 'MyModel',
proxy: {
type: 'rest',
url : 'myurl',
reader: {
type: 'myreader'
}
}
});
Upvotes: 1