1

I have encountered a few sites that uses JSON for request and response
I come across two types :
1- application/x-www-form-urlencoded as request and return a response application/json content type
2- application/json content type for both request and response
in type 1 i tried changing the the response content type using
mIdHttp.Response.ContentType := 'application/json';
but using http analyzer i can see that it doesn't change and its still text/html
now i do not know if the problem is with the fact that i can't change content type or not but i do not know how to deal with json !
a few question regarding json :
1- do i have to encode json data when posting ? how ?
2- how can i parse the json response code ? how to get it ? does it need some kind of encode or special convertion ?
3- what kind of idhttp setting for json changes with each site and needs configuring ?

I understand my questions sound a bit general, but all the other questions are very specific and don't explain the basics when dealing with 'application/json' content type.

Edit 1 :
thanks to Remy Lebeau answer i was able to successfully work with type 1
but i still have trouble sending JSON request, can someone please share an working example, this is one of the sites posting information please use this for your example :
enter image description here

One important note : this particular site's post and request content are exactly like each other ! and it baffles me because at the site, i specify an start date and an end date then click on a folder like icon and this post is sent (the one you can see above), and the result should be links (and it is) but instead of appearing only in request content they also appear in post ! (also i'm trying to get the links but at the post the links, the thing i want, are also being sent, how can i post something i don't have !!?)

just for more clarity here is the place i fill the date and the icon i mentioned :
enter image description here

Ali Ahmadi
  • 93
  • 1
  • 3
  • 12
  • There is no universal solution. Each implementation can be different. You can control if you want Indy to encode parameters using `hoForceEncodeParams` in `FHTTP.HTTPOptions` (if you send JSON data in your request, many sites don't allow encoded request). You should NOT set `Response.ContentType`. That is what server returns. You have to set `Request.ContentType` (what you send) and `Request.Accept` (what you expect from server) – smooty86 Aug 20 '16 at 19:37
  • @smooty86 the `hoForceEncodeParams` flag only applies when posting a `TStrings` in `application/x-www-form-urlencoded` format. It does not apply in this situation, as you cannot post JSON using a `TStrings`, you have to use a `TStream` instead. – Remy Lebeau Aug 20 '16 at 20:03
  • @RemyLebeau you bet I can send JSON in TStrings :) Though I understand it can be less effective. – smooty86 Aug 21 '16 at 07:09
  • You send JSON like any other Post request. Provide your code how you send it. How exactly looks the "Raw stream" with post? It is not not clear in the parsed mode. – smooty86 Aug 21 '16 at 13:37
  • @smooty86 if you post a `TStrings` with `TIdHTTP`, it is expected to be a list of "name=value" pairs, and will be encoded accordingly. I have yet to encounter a website that accepts something like "fieldname=json" as input. Not that it can't, but it is extremely rare. Same goes with XML, too. – Remy Lebeau Aug 21 '16 at 17:42
  • @RemyLebeau If hoForceEncodeParams is off and JSON is one line TStrings, then it will work correctly. No encoding involved. – smooty86 Aug 21 '16 at 19:29
  • @smooty86: It might "work", but that is not how `TIdHTTP` is intended to be used. Why would you use a `TStrings` to send a complete JSON document as a single string? I would suggest using `TStringStream` for that, if not `TMemoryStream` or even `TIdMemoryBufferStream`. – Remy Lebeau Aug 22 '16 at 20:28

1 Answers1

10

You cannot specify the format of the response, unless the requested resource offers an explicit input parameter or dedicated URL for that exact purpose (ie, to request a response be sent as html, xml, json, etc). Setting the TIdHTTP.Response.ContentType property is useless. It will be overwritten by the actual Content-Type header of the response.

To send JSON in a request, you must post it as a TStream, like TMemoryStream or TStringStream, and set the TIdHTTP.Request.ContentType as needed, eg:

var
  ReqJson: TStringStream;
begin
  ReqJson := TStringStream.Create('json content here', TEncoding.UTF8);
  try
    IdHTTP1.Request.ContentType := 'application/json';
    IdHTTP1.Post(URL, ReqJson);
  finally
    ReqJson.Free;
  end;
end;

To receive JSON, TIdHTTP can either

  1. return it as a String (decoded using a server-reported charset):

    var
      ReqJson: TStringStream;
      RespJson: String;
    begin
      ReqJson := TStringStream.Create('json content here', TEncoding.UTF8);
      try
        IdHTTP1.Request.ContentType := 'application/json';
        RespJson := IdHTTP1.Post(URL, ReqJson);
      finally
        ReqJson.Free;
      end;
      // use RespJson as needed...
    end;
    
  2. write the raw bytes to an output TStream of your choosing:

    var
      ReqJson: TStringStream;
      RespJson: TMemoryStream;
    begin
      RespJson := TMemoryStream.Create;
      try
        ReqJson := TStringStream.Create('json content here', TEncoding.UTF8);
        try
          IdHTTP1.Request.ContentType := 'application/json';
          RespJson := IdHTTP1.Post(URL, ReqJson, RespJson);
        finally
          ReqJson.Free;
        end;
        RespJson.Position := 0;
        // use RespJson as needed...
      finally
        RespJson.Free;
      end;
    end;
    

The HTTP response code is available in the TIdHTTP.Response.ResponseCode (and TIdHTTP.ResponseCode) property.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • what you said helped me with the `first type`, but i still have problem with `second type`, i edited my question can you please read it and answer me accordingly, Thank you very much! – Ali Ahmadi Aug 21 '16 at 11:11
  • @AliAhmadi what exactly are you having trouble with? Your edit does not make it any clearer. What is so hard about putting the JSON content as-is into a `TStream` descendant and then posting it? Do you know how to produce JSON in the first place? – Remy Lebeau Aug 21 '16 at 17:45
  • what do you mean by `produce JSON`, maybe that is my problem ? (as i said, i do not know the basics about `JSON`, a simple example would be more than enough, thx) – Ali Ahmadi Aug 21 '16 at 19:33
  • 3
    @AliAhmadi: I have added examples to my answer. But how do you expect to send the JSON if you don't know how to produce it in the first place? See [Embarcadero's JSON documentation](http://docwiki.embarcadero.com/RADStudio/en/Json). – Remy Lebeau Aug 22 '16 at 20:35