1

I am trying to write a client application which consumes a Mashape API service using Delphi XE3 and Indy10, but I have run into a bit of a snag.

Here is what I have tried:

I placed TIdHTTP andTIdSSLIOHandlerSocketOpenSSL components on my form and linked them together using the TIdHTTP.IOHandler property. I then placed a button and memo on my form and placed the following bit of code on the buttons OnClick event:

procedure TForm1.Button2Click(Sender: TObject);
begin
 IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
 IdHTTP1.Request.CustomHeaders.AddValue('X-Mashape-Key: ','<my_api_key>');
 Memo1.Lines.Text := IdHTTP1.Get('https://hbrd-v1.p.mashape.com/anime/log-horizon');
end;

I then start up my app and when I press the button the app will wait for a moment and then spit out a HTTP/1.1 403 Forbidden error message. Pressing the button a 2nd time will cause a HTTP/1.1 500 Internal Service Error message.

I already checked to see if I had the needed SSL Library files on my system and I do, and I have tested my credentials time and time again and they appear to be correct, and I know the url is correct, so I must be missing something in my code to cause these errors to display. I was hoping someone with more experience in this area might be able to offer some advice.

Update: here is TRESTClient code that works:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IPPeerClient, Vcl.StdCtrls,
  REST.Response.Adapter, REST.Client, Data.Bind.Components,
  Data.Bind.ObjectScope;

type
  TForm1 = class(TForm)
    RESTClient1: TRESTClient;
    RESTRequest1: TRESTRequest;
    Button1: TButton;
    Memo1: TMemo;
    RESTResponse1: TRESTResponse;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 RESTClient1.BaseURL := 'https://hbrd-v1.p.mashape.com/anime/log-horizon';
 RESTRequest1.Execute;
 Memo1.Lines.Text := RESTResponse1.Content;

// The only thing not shown here is the RESTRequest1.Params which are
// Name: 'X-Mashape-Key'
// Value: 'my-api-key'
// Kind: pkHTTPHEADER
// Everything else is included here which isn't much.
end;

end.

I want to do the same thing with TIdHTTP.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
nosx
  • 145
  • 1
  • 2
  • 9

1 Answers1

2

It is hard to know what is actually happening without seeing the actual HTTP messages going back and forth. When an HTTP response indicates an error, an EIdHTTPProtocolException exception is raised, and its ErrorMessage property contains the body of the server's response. Does it give you any indication about why the error occurred?

However, you do need to change this:

IdHTTP1.Request.CustomHeaders.AddValue('X-Mashape-Key: ','<my_api_key>');

To this:

IdHTTP1.Request.CustomHeaders.Values['X-Mashape-Key'] := '<my_api_key>';

And get rid of the programmic IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1; assignment, since you already handled that in the form designer.

Aside from that, a 403 error means your credentials are NOT accepted by the server. I don't see you assigning any credentials to the TIdHTTP.Request.Username and TIdHTTP.Request.Password properties in your code, are you doing that in the form designer?

TIdHTTP uses a plugin system for handling HTTP authentication schemes. If the server allows BASIC authentication, you can set the TIdHTTP.Request.BasicAuthentication property to true so BASIC is used as a default when no other authentication scheme is available. You can use the TIdHTTP.OnSelectAuthorization event to see which authentications the server actually supports.

If the server wants a non-BASIC authentication, you will need to add the relevant IdAuthentication... to your uses clause to enable that plugin. For example, IdAuthenticationDigest for DIGEST authentication, IdAuthenticationNTLM for NTLM authentication, etc. Or, add the IdAllAuthentications unit instead to enable all of the plugins.

If you need to use an HTTP authentication that Indy does not support (OATH, for instance), you can either:

  1. use TIdHTTP.Request.CustomHeaders.Values['Authorization'] to provide the relevant credential data manually.

  2. implement a custom TIdAuthentication-derived class, and assign an instance of it to the TIdHTTP.Request.Authorization property, or its class type to the VAuthenticationClass parameter of the TIdHTTP.OnSelectAuthorization event.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I made the changes per your instructions and even after adding my username and password to the request (they are not required btw) and checking Basic Authentication being TRUE or FALSE. The errors still occur. What is strange to me is that I used the exact same values in the TRestClient contols and they work just fine, but they are too slow for my needs which is why I wanted to use INDY instead in the hope that it would be faster. I am unsure how to proceed now. – nosx Jul 09 '14 at 01:34
  • `TRESTClient` uses `TIdHTTP` internally. If you capture the raw HTTPS request being sent by `TRESTClient` ([Fiddler](http://www.telerik.com/fiddler) supports HTTPS, and `TRESTClient` has `ProxyServer/ProxyPort` properties), you can configure `TIdHTTP` to replicate the request values as needed. Or, show your `TRESTClient` code, and I will translate it to `TIdHTTP` for you. – Remy Lebeau Jul 09 '14 at 01:37
  • Here is a Pastebin of the Unit from the TRESTClient version: http://pastebin.com/7HitQDCX I hope this is what you were looking for anyway, it's extremely simple, but it works, it's just abit slow when fetching results. – nosx Jul 09 '14 at 02:41
  • 1
    For future reference, don't post your code to pastebin or any other external site. Embed the code directly in your question. I have updated your question for you, and will get you a `TIdHTTP` translation soon. – Remy Lebeau Jul 09 '14 at 05:34
  • just checking in to see if you managed to get this working with INDY like it does with the Rest client? If you need my api key to test with I can share it with you. – nosx Jul 13 '14 at 04:36
  • Sorry, I have not had time to look at it yet. But I have not forgotten about it. – Remy Lebeau Jul 13 '14 at 04:56
  • No problem, you are doing me a favor so no rush and thanks once again for your assistance – nosx Jul 13 '14 at 20:29