1

I'm sending JSON to a restful service using TidHTTP.Post but having trouble reading the response from idHTTP when an HTTP error 400 occurs. When a 400 occurs, the server provides JSON which describes errors in the data being sent. I get readable JSON results sometimes but most of the time the response contains only a couple of unprintable characters.

procedure TForm1.SendData(const stlACSchedule: TStringList; BatchTimeIn: TDateTime);
var
  TargetURL : String;
  stsJson: TStringStream;
  myResponse : String;
  resp : TMemoryStream;

begin
  TargetURL := 'http://sandbox.xxxxxxxxxxx.com/api/v1/feeds' ;
  stsJson := TStringStream.Create;

  stsJson.WriteString(stlACSchedule.Text);

  resp := TMemoryStream.Create;
  application.ProcessMessages;
  try
    myResponse := IdHTTP1.Post( TargetURL, stsJson );
    WriteStatus( 'Response from Vendor Server:   ' );
    UpdateUploadStatus2( IdHTTP1.ResponseCode, IdHttp1.ResponseText, BatchTimeIn, 'usPending', 'usUploaded' );

  except
    on E: EIdHTTPProtocolException do begin
      WriteStatus( 'HTTP Protocol Error from Vendor Server: ' + #13 + E.ErrorMessage + ' -*- ' + IdHTTP1.ResponseText );
      UpdateUploadStatus2( IdHTTP1.ResponseCode, E.ErrorMessage + ' - ' + IdHTTP1.ResponseText, BatchTimeIn, 'usPending', 'usBatchFail' );
      ShowMessage('Fubar_!: ' + myResponse);
    end;

    on E: Exception do begin
      WriteStatus( 'Unknown Error from Vendor Server:' );
      UpdateUploadStatus2( IdHTTP1.ResponseCode, E.Message + ' - ' + IdHTTP1.ResponseText, BatchTimeIn, 'usPending', 'usBatchFail' );
      ShowMessage('Fubar!: ' + myResponse);
    end;
  end;
  resp.free;
  stsJson.free;

end;  { SendData }

procedure TForm1.WriteStatus(strTextIn : String);
begin
  Memo1.Lines.add('');
  Memo1.Lines.add(strTextIn);
  Memo1.Lines.add(IntToStr(IdHTTP1.ResponseCode));
  Memo1.Lines.add(IdHTTP1.ResponseText);
end;  { WriteStatus }

It appears that the EIdHTTPProtocolException exception handler is catching the error but most of the time I get responses like this (there are 3 unprintable characters below the "HTTP Protocol Error from Vendor Server" line):

HTTP Protocol Error from Vendor Server: 

400
HTTP/1.1 400 Bad Request

but occasionally I get a good response, like this:

HTTP Protocol Error from ReturnJet Server: 
{"errors":[{"code":7,"message":"Invalid departure or destination type for event: 1"}]} -*- HTTP/1.1 400 Bad Request
400
HTTP/1.1 400 Bad Request

It looks like it may have something to do w/ the length of the response but I'm not sure.

What do I need to do to consistently decode the ResponseText?

I'm using: Delphi XE8, Indy ver 10.6

PS - when I Post this data manually using Postman, I always get the full JSON response.

TIA

2 Answers2

0

A 400 response is an error response. By default, TIdHTTP raises an EIdHTTPProtocolException exception when an HTTP error occurs (unless you ask it not to), where the HTTP response headers are available in the TIdHTTP.Response property, and the HTTP response content is available as a string in the exception's ErrorMessage property, so as not to corrupt whatever TStream is used for output (unless you ask for it).

If the exception's ErrorMessage does not contain the JSON you are expecting, then either the server is not sending JSON to begin with, or the JSON is not being transmitted in a format that Indy can decode to a string. But you didn't show what the actual HTTP responses look like, or what the "3 unprintable characters" actually are, so there is no way to know for sure why the ErrorMessage is not being populated as you are expecting.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Sorry, but JavaScript in browser can display the returned text without problems. Only TIdHTTP cannot. – Paul Nov 02 '22 at 16:17
  • @Paul I know for a fact that `TIdHTTP` works correctly and DOES provide access to the error content when the code and the responses are correct. So, without seeing your actual code, your setup, or the responses you are receiving, I can't help you to understand why the content is not available where/how you are expecting it. Feel free to post your own question about whatever issue you are experiencing. – Remy Lebeau Nov 02 '22 at 17:21
  • Already done. https://stackoverflow.com/questions/74292871/indy-doesnt-get-response-text-returned-with-error-404 – Paul Nov 02 '22 at 17:24
  • @Paul I have posted an answer for that question – Remy Lebeau Nov 02 '22 at 17:33
0

You have to change some options on IdHTTP in order to get the same response as you get on the browser or programs like Postman.

Use:

IdHTTP1.HTTPOptions := idHTTP1.HTTPOptions + [hoNoProtocolErrorException, hoWantProtocolErrorContent];
  • I am using delphi xe4 and when I make the post with the postman it returns 400 bad request but it returns me in the content of the error, and from delphi when I make the post it says 400 bad request but it does not return the error. – Raidel Fonseca Aug 05 '20 at 12:23
  • There is no `hoWantProtocolErrorContent` option. – Paul Nov 02 '22 at 16:15
  • @Paul Yes, there is: `type ... TIdHTTPOption = (..., hoNoProtocolErrorException, ... hoWantProtocolErrorContent, ...);` The `hoWantProtocolErrorContent` option was added way back in 2016 (https://www.indyproject.org/2016/01/10/new-tidhttp-flags-and-onchunkreceived-event/), so if you don't have it available in your version of Indy then you are using an outdated version and need to upgrade. – Remy Lebeau Nov 02 '22 at 17:14
  • @MarcelinoMaxPinheiro I don't want to downvote your answer, but it is misleading. You ARE NOT required to enable those 2 options just to *access* the error content. It is possible to access the error content without enabling those options (by handling `EIdHTTPProtocolException`, as the OP was already doing). The 2 options simply make it *easier* to access the error content (ie, as direct output of `Post()`) without dealing with `EIdHTTPProtocolException`, that's all. Whatever is stopping `EIdHTTPProtocolException.ErrorMessage` from getting the error content is unrelated to those options. – Remy Lebeau Nov 02 '22 at 17:19
  • @RemyLebeau apparently you "don't want" but did it anyway... I've posted this answer case worked for me. No problem. – Marcelino Max Pinheiro Nov 03 '22 at 15:33