Search code examples
restdelphifiremonkey

How to use a REST API with FireMonkey?


I need to implement a REST API in FireMonkey to get some information, but I'm not sure how I can do it.

The REST API uses OAuth2, I have access to two codes: Consumer Key and Consumer Secret. After this, I need to get a temporary Bearer token.

To request the temporary token, it is necessary to perform an HTTP POST request to the Token endpoint https://apigateway.serpro.gov.br/token, informing the access credentials (consumerKey: consumerSecret) in the HTTP Authorization Header, in base64 format, as shown below.

[POST] grant_type = client_credentials 
[HEAD] Authorization: Basic Base64 (Consumer key: ConsumerSecret)

How can I get the access token with Delphi?


Solution

  • The OAuth2 component coming with the Delphi REST Framework do sadly not work when the authentication method is client_credentials, so you have to do it the manual way. I've included the test code I used for finding out how it worked. Even tested it again today just to make sure that it works :)

    Drop a Memo and a button on the form and set the Button1 OnClick event, change the <your_xxxx> to what suits you and you should be good to go (just check that it is named Memo1, Button1 and Form1)

    You will have access to the REST components with Firemonkey too, so this is just to show of the REST framework.

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows,
      Winapi.Messages,
      System.SysUtils,
      System.Variants,
      System.Classes,
      Vcl.Graphics,
      Vcl.Controls,
      Vcl.Forms,
      Vcl.Dialogs,
      Vcl.StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
        GaToken: string;
        GaTokenType: string;
        GaTokenExpire: integer;
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    uses
      REST.Types,
      REST.Client,
      REST.Utils,
      System.NetEncoding,
      System.Net.HttpClient;
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      vClientId,
        vClientSecret,
        vScope,
        aExpire: string;
      LClient: TRESTClient;
      LRequest: TRESTRequest;
      LResponse: TRESTResponse;
    begin
      // Scope is not mandatory and can be skiped
      vClientId := '<your_clientID>';
      vClientSecret := '<your_seecret>';
      // vScope := '<Your_scope>;
    
      LClient := TRESTClient.Create('<YOUR_TOKEN_URL>');
      try
        LRequest := TRESTRequest.Create(LClient);
        try
          LResponse := TRESTResponse.Create(LClient);
          try
            LRequest.Client := LClient;  // This line is not really needed but it is good for code readability, see TRESTRequest.Create(LClient);
            LRequest.Response := LResponse;
    
            LRequest.Method := rmPOST;
            LRequest.AddAuthParameter('grant_type', 'client_credentials', pkGETorPOST);
            LRequest.AddAuthParameter('client_id', vClientId, pkGETorPOST);
            LRequest.AddAuthParameter('client_secret', vClientSecret, pkGETorPOST);
            // LRequest.AddAuthParameter('scope', vScope, pkGETorPOST);
    
            LRequest.Execute;
    
            LResponse.GetSimpleValue('access_token', GaToken);
            LResponse.GetSimpleValue('token_type', GaTokenType);
            LResponse.GetSimpleValue('expires_in', aExpire);
            GaTokenExpire := aExpire.ToInteger;
    
            Memo1.Clear;
            Memo1.Lines.Add(IntToStr(LResponse.StatusCode) + ' / ' + LResponse.StatusText);
            Memo1.Lines.Add('------------   R A W   R E S P O N S E   ---------------------');
            Memo1.Lines.Add(LResponse.Headers.Text);
            Memo1.Lines.Add('--------------------------------------------------------------');
            Memo1.Lines.Add(LResponse.Content);
            Memo1.Lines.Add('--------------------  T O K E N  -----------------------------');
            Memo1.Lines.Add(GAToken);
          finally
            LResponse.Free;
          end;
        finally
          LRequest.Free;
        end;
      finally
        LClient.Free;
      end;
    end;
    
    end.