RTC Forums
April 20, 2024, 04:52:29 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: 1 [2]
  Print  
Author Topic: Returning data in JSON format  (Read 13923 times)
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #15 on: February 11, 2010, 06:12:27 PM »

Can you please check if your iPhone app is sending the request using HTTP/1.0? To do this from your RTC Server, simply check the state of the Request.Close property. If it is TRUE, then the request was received using HTTP/1.0 and the client might be expecting a response in HTTP/1.0 but will receive a HTTP/1.1 response.

I am already preparing an update for the RTC SDK which will extend the rtcHttpServer component to always respect the HTTP protocol used by the client and respond using the same protocol version (as said, the current implementation always sends a HTTP/1.1 response out). If the client is sending a HTTP/1.0 request, the update which I am currently preparing should fix the problem.

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #16 on: February 11, 2010, 07:01:42 PM »

RTC SDK 3.50 is now ready for download, including a fix for working with HTTP/1.0 clients which expect a HTTP/1.0 response and can not process a response if it was sent using the HTTP/1.1 header.

Best Regards,
Danijel Tkalcec
Logged
garyk1968
Newbie
*
Posts: 16


« Reply #17 on: February 11, 2010, 08:31:14 PM »

1) Is your rtcDataProvider component linked to your RtcHttpServer component (through its "Server" property)?

Yes it is linked.

2) Have you implemented the "OnCheckRequest" event on your rtcDataProvider component and are you calling "Accept" in that event to accept the request which you want to process?

Yes the code is;
  with Sender as TRtcDataServer do
  begin
    Memo1.Lines.Add(Request.FileName);
    Memo1.Lines.Add(Request.Query.Value['index']);

    if Request.FileName = '/' then
       Accept;

    if UpperCase(Request.FileName) = '/GET/CUSTOMERS' then
       Accept;
  end;


3) Have you implemented the "OnDataReceived" event on your rtcDataProvider component to wait until the complete request has been received from the client (Request.Complete=TRUE) before you start processing the request and sending a response out?

Yes code is;
var
  sResult: string;
begin
  with Sender as TRtcDataServer do
  begin
    if Request.Complete then
    begin
      if Request.Filename = '/' then
        Write('<H1>Test Server Running</H1>');
      if UpperCase(Request.FileName) = '/GET/CUSTOMERS' then
      begin
        sResult := dmSRV.GetCustomers(Request.Query.Value['index']);
        //Response.ContentType := 'application/json;charset=UTF-8'; -commented out to test on screen vs saving to file
        Write(sResult);
      end;
    end;
  end;
end;

4) What do you mean by "not sending anything back"? If you use the Write method from the Sender:TRtcConnection parameter in the OnDataReceived event, data will be sent out. Is it possible you are calling the Write() procedure from Delphi instead of using the Write() method from the Sender:TRtcConnection component?

I mean that nothing is coming back to the iphone application, I am debugging it and setting a breakpoint to test the return value which is always nil.

I have tried the url via the safari browser on the iphone simulator and that just throws up a 'safari cannot download this file' error. I have disabled the firewall on the windows box (testing it against server on the separate box rather than the windows running on vmware on the mac) running out of things try now Sad

Best regards


Gary
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #18 on: February 11, 2010, 09:07:49 PM »

Even though I would recommend using a separate rtcDataProvider component for the '/' request to avoid having to check the Request.FileName value in the OnDataReceived event, your implementation is generally fine the way it is now. I'd just change the response for the '/' request to '<html>Server running</html>' instead of using '<h1></h1>' to make sure the Browser recognizes it as a HTML page.

Are you able to get a web page displayed in Safari if you just enter the IP address of your Server PC in Safari's Address field? Since you have the '/' request handler implemented, this should work regardless of your JSON implementation.

If you see that your Server is being accessed (requests pop up in Memo1), my guess is that your problem is either related to the HTTP/1.1 vs HTTP/1.0 issue, which I've mentioned above and have fixed in the latest RTC SDK 3.50 update, or ... it's a problem of the iPhone emulator not being able to connect to your PC.

To eliminate the HTTP/1.0 vs HTTP/1.1 issue (or confirm it?), please extend your OnCheckRequest event to print out the state of the Request.Close property, for example like this ...

with Sender as TRtcDataServer do
  begin
    Memo1.Lines.Add(Request.FileName);
    Memo1.Lines.Add(Request.Query.Value['index']);
    if Request.Close then
      Memo1.Lines.Add('!!! HTTP/1.0 !!!');

    if Request.FileName = '/' then
       Accept;

    if UpperCase(Request.FileName) = '/GET/CUSTOMERS' then
       Accept;
  end;

... And let me know if HTTP/1.0 will be added in the memo when a request comes from iPhone.

If the Server gets a request from the Client (you see it added to Memo1), then your problem has nothing to do with firewalls. A firewall would completely block communication and you would not get anything on the Server.

So ... before we continue, can you please let me know:

1) Is your Server receiving a request from your iPhone app and logging in in Memo1?

2) If your Server is receiving a request from your iPhone app, is the value of the Request.Close property TRUE or FALSE in the OnCheckRequest event when the request is received from iPhone?

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #19 on: February 11, 2010, 09:31:18 PM »

I have Xcode and the iPhone Simulator Version 3.0 (138) installed on my MacMini (running OSX 10.5.Cool, so I've tested if the iPhone Simulator has problems accessing the LAN, but that is not the case. Safari running in the iPhone Simulator was able to connect to a RTC Server running on my main PC (which is running Windows Vista) and display the web page provided by the RTC Server. But you've said you are running Windows inside a VM and VMs use virtual network cards, but if you can access your RTC Server from Safari on Mac OSX, you should be able to access it from Safari running inside the iPhone Simulator. If you can't access your RTC Server from Safari running on Mac OSX, the problem could be in the way network is configured in your VM.

Best Regards,
Danijel Tkalcec
Logged
garyk1968
Newbie
*
Posts: 16


« Reply #20 on: February 11, 2010, 09:35:50 PM »

Are you able to get a web page displayed in Safari if you just enter the IP address of your Server PC in Safari's Address field? Since you have the '/' request handler implemented, this should work regardless of your JSON implementation.

... And let me know if HTTP/1.0 will be added in the memo when a request comes from iPhone.




1) Is your Server receiving a request from your iPhone app and logging in in Memo1?

response gets received and I see the value of 'index' in the memo field from the iphone request

2) If your Server is receiving a request from your iPhone app, is the value of the Request.Close property TRUE or FALSE in the OnCheckRequest event when the request is received from iPhone?

and is coming in as http1.1 request.close is false


best regards


Gary
Logged
garyk1968
Newbie
*
Posts: 16


« Reply #21 on: February 11, 2010, 09:38:57 PM »

I have Xcode and the iPhone Simulator Version 3.0 (138) installed on my MacMini (running OSX 10.5.Cool, so I've tested if the iPhone Simulator has problems accessing the LAN, but that is not the case. Safari running in the iPhone Simulator was able to connect to a RTC Server running on my main PC (which is running Windows Vista) and display the web page provided by the RTC Server. But you've said you are running Windows inside a VM and VMs use virtual network cards, but if you can access your RTC Server from Safari on Mac OSX, you should be able to access it from Safari running inside the iPhone Simulator. If you can't access your RTC Server from Safari running on Mac OSX, the problem could be in the way network is configured in your VM.

Best Regards,
Danijel Tkalcec

Yes your right the VM does strange things which is why I am using a separate windows box. It even gives the VM an IP not in the range of my router which is strange. Anyway its now a simple communication between the iphone, my app or safari and another windows machine on my network running the server.


Just as an update I am now grabbing an error message which should help, from cocoa I am getting an error  261 which is a 'Read error because the string encoding was not applicable.' as I have to specify a type of string encoding and I am using UTF8 which works fine for other sites but this maybe the problem.

cheers

Gary
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #22 on: February 11, 2010, 09:59:11 PM »

Ok, so the request is sent from your iPhone app and received by the RTC Server. What about the response sent from the RTC Server to the iPhone app? Are you using some JSON-specific library to send the request and receive a response, or are you using general-purpose sockets or HTTP transports?

Can you modify your iPhone app to send a HTTP request to the Server and show the response (what ever received) in a scrollable text box (in the iPhone app), or do anything which would get us a step further to see if the code you are using on the iPhone is receiving a response but is unable to parse JSON data, or if the problem is really that no response is received by the app running inside your iPhone Simulator?

Can you post the code you are using on the iPhone side, be it in Objective-C, C, C++ or Objective-Pascal, so I can also do my own debugging and see what is happening, or have you already solved the problem and its all working now?

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #23 on: February 11, 2010, 10:07:45 PM »

Ah, just read your updated reply. That is a big progress from "not receiving anything" Wink

You need to know that the RTC SDK does not automatically encode nor decode any data being sent nor received. You read and write data using the AnsiString type, so you need to do proper encoding and decoding.

If you are working with Delphi 2009 and later, which have Unicode support, and the code you are using on the iPhone understands UTF-8, you can use the Utf8Encode function from the rtcInfo unit to convert your UnicodeString to a valid UTF-8 encoded AnsiString. If you set the ContentType correctly ('application/json;charset=UTF-8' looks fine to me) and use Utf8Encode on the string before sending, it might do the trick:

Response.ContentType:='application/json;charset=UTF-8';
Write(Utf8Encode(sResult));

Please let me know if that solves your problem.

Best Regards,
Danijel Tkalcec
Logged
garyk1968
Newbie
*
Posts: 16


« Reply #24 on: February 12, 2010, 08:42:11 AM »

Hi Danijel,

Finally! What was it? a freakin pound sign '£'!!

So this is valid

{"Results":[{"account_ref":"AAB010","name":"A A Barnfield","balance":"0.00"}]}

this errors

{"Results":[{"account_ref":"AAB010","name":"A A Barnfield","balance":"£0.00"}]}

So I have it working!

Many thanks for all your help and patience it is most appreciated. If you do dip your toe in the ObjC/Cocoa waters and need help feel free to ask me any questions at gary@nospam.domorewithsage.com obviously taking the nospam bit out. I'm a long term delphi dev (since D1) and it took me a while to get my head around iphone development as it is such a different approach.

I need to buy a licence for your product anyway as this will form part of a commercial product.

Thanks again


Gary
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #25 on: February 12, 2010, 10:41:07 AM »

Finally! Smiley

I'm glad you've found and solved the issue, but I am wondering why a pound sign put inside a string would be a problem. From your reply, it looks like the value for "balance" was sent as a string and not as a numeric, which means that using a pound sign should be allowed.

A short look at http://www.json.org/ does make it look like schema definition is not absolutely necessary for parsing JSON data, which would mean that parsing "balance":"L0.00" should work, but a pound sign would probably have to be encoded. I'm not sure what to make of * Any UNICODE character except " or \ or control character *, but shouldn't Utf8Encode() do the trick when charset in ContentType is set to UTF-8?

In other words ... could you problem also be solved without removing the pound sign from the original string by using the Utf8Encode function from the rtcInfo unit to get it encoded to UTF-8 (provided the string does not have " or \ or a control character -> what ever that is)?

...
uses rtcInfo;
...
Write(Utf8Encode(sResult));
...


If you would be sending the value for "balance" as a number (without enclosing it inside quotation marks), a pound sign would not be allowed, but since you are sending it as a string !?!? hmm ... food for thought.

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #26 on: February 12, 2010, 11:21:17 AM »

In other words ... a pound sign was making you trouble in this particular data sample, but if you do not encode your strings properly, you will get more problems once you try sending other Unicode strings (for example, using the name 'Müller' for the field 'name' would most likely start the alarm again).

But using Utf8Encode on the string you are sending out would not handle all the cases. You will need to write a function for converting \ and " as well as other 'control characters' to the accepted JSON string format (see http://www.json.org ).

Also, to avoid conversions from string to numerics on the Client, you might want to send numeric values without quotes ...
{"Results":[{"account_ref":"AAB010","name":"A A Barnfield","balance":0.00}]}

I may be wrong here, but if I've understood the JSON format correctly, it looks like "Results" is an array but you are sending all your parameters as a single object inside the array, which means that you should also be able to use { } instead of [{ }] to send your result parameters (provided you do not expect more than one result) ...
{"Results":{"account_ref":"AAB010","name":"A A Barnfield","balance":0.00}}

Since you do not seem to be using the JSON-RPC format and Results is currently holding a single object, enclosing all parameters inside a separate "Results" object might also be unnecessary, so your result would probably also be valid if sent like ...
{"account_ref":"AAB010","name":"A A Barnfield","balance":0.00}

Naturally, all of this depends on what the client is expecting on the other side. If the client is expecting a Result array which could have more than one element and each element can be an object, then the full format you are using is necessary.

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #27 on: February 12, 2010, 11:49:39 AM »

I've just found the RFC 4627, which (according to http://en.wikipedia.org/wiki/JSON ) completely describes the JSON format:
http://tools.ietf.org/html/rfc4627

Interesting to note here are sections 2.5 and 3, which describe the String format and String Encoding.

Best Regards,
Danijel Tkalcec
Logged
garyk1968
Newbie
*
Posts: 16


« Reply #28 on: February 12, 2010, 12:59:50 PM »

In other words ... a pound sign was making you trouble in this particular data sample, but if you do not encode your strings properly, you will get more problems once you try sending other Unicode strings (for example, using the name 'Müller' for the field 'name' would most likely start the alarm again).

Yes as soon as I had the encoding error I thought to myself I bet its to do with certain characters, it woke me at 6am and I had to go and see if that was the case!

But using Utf8Encode on the string you are sending out would not handle all the cases. You will need to write a function for converting \ and " as well as other 'control characters' to the accepted JSON string format (see http://www.json.org ).

I didnt get around to using the UTF8encode but I will put the pound sign back in and try it and see what happens!

Also, to avoid conversions from string to numerics on the Client, you might want to send numeric values without quotes ...
{"Results":[{"account_ref":"AAB010","name":"A A Barnfield","balance":0.00}]}

I may be wrong here, but if I've understood the JSON format correctly, it looks like "Results" is an array but you are sending all your parameters as a single object inside the array, which means that you should also be able to use { } instead of [{ }] to send your result parameters (provided you do not expect more than one result) ...
{"Results":{"account_ref":"AAB010","name":"A A Barnfield","balance":0.00}}

Since you do not seem to be using the JSON-RPC format and Results is currently holding a single object, enclosing all parameters inside a separate "Results" object might also be unnecessary, so your result would probably also be valid if sent like ...
{"account_ref":"AAB010","name":"A A Barnfield","balance":0.00}

Yes I wasnt sure whether to include the numeric in quotes or not, I need to re-read the JSON specification.

As to regards {} instead of [{}] the result set is returning multiple rows I just edited to contain one record but you are correct for a single entry you *could* do that although I am iterating through an array of 1..n elements based on what is inside the [].

As for your propsoal of supporting JSON that would be great although its quite easy to construct it using a normal TDataSet descendant just iterating through the result set and building the string.

Best Regards


Gary
Logged
Pages: 1 [2]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.034 seconds with 16 queries.