You are not logged in.
Pages: 1
What would be the correct format to send a named dynamic array to an interface function?
I declared the following as a test:
TFilterType = record
name: string;
value: string;
comparetype: string;
end;
TFilterList = array of TFilterType;
...
function TStaff.FilterStaff(const filters: TFilterList): TFilterList;
begin
Log('Received filters: '+IntToStr(length(filters)) );
setlength(result, 2);
result[0].name := 'name1';
result[0].value := 'value1';
result[0].comparetype := '>';
result[1].name := 'name2';
result[1].value := 'value2';
result[1].comparetype := '=';
end;
The function correctly returns
{"result":[[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype"
:"="}]]}
But when sending
var dataString = {"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]};
...
http://localhost:8080/root/Staff/FilterStaff?filters%5B0%5D%5Bname%5D=name1&filters%5B0%5D%5Bvalue%5D=value1&filters%5B0%5D%5Bcomparetype%5D=%3E&filters%5B1%5D%5Bname%5D=name2&filters%5B1%5D%5Bvalue%5D=value2&filters%5B1%5D%5Bcomparetype%5D=%3D&session_signature=3eaeb14d00379c791c58bcc3
an empty array is received.
Offline
Unfortunately posting the values causes a 406 Not Acceptable error.
var dataString = {"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]};
jQuery.ajax({
type: "POST",
dataType: "json",
url: MAIN_URL + '/Staff/FilterStaff',
data: dataString,
timeout: 2000
});
Offline
I guess a workaround would be making a wrapper function around TStaff.FilterStaff() which accepts json string instead, But definitely it's perfect if @ab can fix it.
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
Thanks edwin. I can do a wrapper function and then just use that when calling via ajax and use the real function for delphi clients. However, I suspect this will add a lot of overhead and will need to be done throughout.
Any suggestions what would be the most efficient way of converting the json string to the array?
Offline
Check in TServiceMethodExecute.ExecuteJson where it fails to parse input content.
Are you sure the body is really some valid JSON?
I'm afraid you are sending some string over the wire.
Also try to define the record as "packed record", and try text-based serialization.
Offline
Problem found! packed record did not make a difference, but ab put me on the right track. For future ajax users, send the json as string, not object. To correct the example above, I changed
var dataString = {"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]};
to
var dataString = '{"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]}';
However this messes up appending the session signature when using GET. So Post is forced.
In TServiceMethodExecute.ExecuteJson's case statement, Par^ detects the first character as f and not as { when parsing. Adding the quotes resolved it.
Last edited by squirrel (2015-10-05 12:27:39)
Offline
Looks like the parsing is very fragile. Adding more parameters to the function highlights that some exact format is required, even though it succeeds in browser parsing.
Changing the function to:
function TStaff.FilterStaff(const filters: TFilterList; Limit: integer): TFilterList;
and the datastring to
var dataString = '{"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}], "Limit":"100"}';
gives the 406 same issue again, but the json validates successfully on sites such as jsonschema.
Using this format, works, provided that the correct type (integer vs string) is passed. Note that this json doesnt validate on sites such as jsonschema.net:
var dataString = '{"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]}, {"Limit":"100"}';
This works for integer Limit parameter:
var dataString = '{"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]}, {"Limit":100}';
Last edited by squirrel (2015-10-05 13:28:31)
Offline
Please try to see in TServiceMethodExecute.ExecuteJson why
var dataString = '{"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}], "Limit":"100"}';
does not work.
Offline
I suspect the browser had a cached version of the js file where the value 100 was "100" ie as a string. It is working now after clearing caches. Thanks ab!
Offline
If you want to send the data as JSON, you have to encode it first:
var dataString = {
"result" : [[{
"name" : "name1",
"value" : "value1",
"comparetype" : ">"
}, {
"name" : "name1",
"value" : "value2",
"comparetype" : "="
}
]]
};
jQuery.ajax({
type : "POST",
dataType : "json",
contentType : "application/json; charset=utf-8",
url : 'http://localhost:8080/root/MyService.FilterStaff',
data : JSON.stringify(dataString)
});
Offline
I've tried to reproduce the issue, but found none.
Offline
Pages: 1