Overview
Description
TMS FNC Cloud Pack is a set of components to access and use existing cloud services via REST.
Availability
Supported frameworks and platforms
- VCL Win32/Win64
- FMX Win32/Win64, macOS, iOS, Android, Linux
- LCL Win32/Win64, macOS, iOS, Android, numerous Linux variants including Raspbian
- WEB: Chrome, Edge, Firefox, …
Supported IDE’s
- Delphi 10 Seattle and C++ Builder 10 Seattle or newer releases
- Lazarus 1.4.4 with FPC 2.6.4 or newer official releases
- TMS WEB Core for Visual Studio Code 1.3 or newer releases ma
Important notice
TMS FNC Cloud Pack requires TMS FNC Core (separately available at the My Products page)
Registering your application
Most services require authentication and authorization before use. A first step will be to register your application with the different cloud services so you can obtain an application key, secret and callback URL. Please refer to our online documentation for detailed instructions.
Getting Started
Once your application is registered and you have the required authorization information, you can get started to get access to the cloud service(s). Most components work in a similar way and use one of the following two techniques:
A) Client ID and Client Secret with Callback URL
-
Drop the component on the form
-
Set up the required authorization information by providing the Client ID, Client Secret, and Callback URL values through the
.Authentication.ClientID
,.Authentication.Secret
, and.Authentication.CallbackURL
properties. For services that require additional or different information, refer to the detailed instructions under the specific service topic. -
Call the
.Connect
method -
The login screen of the service is displayed in a separate browser window
-
After successful authentication, the
OnConnected
event is triggered and from that moment the component has access the cloud service API
B) API Key
-
Drop the component on the form
-
Setup the required authorization information by providing the API Key value through the
.Authentication.Key
property. For services that require additional or different information, refer to the detailed instructions under the specific service topic. -
If the API key is valid, the component has access to the cloud service API
Implement a custom service
After installing the TMS FNC Cloud Pack, you’ll have access to the unit *TMSFNCCloudOAuth.pas
. Depending on the framework, you’ll need to prefix the unit with FMX.
, VCL.
, WEBLib.
or LCL
. The samples and explanation in this document is based on FMX, but actually applies to all supported frameworks. There are 2 classes that can be used for implementing a custom service:
TTMSFNCCloudOAuth
(base class for accessing and implementing REST services based on OAuth 2.0 authentication)TTMSFNCSimpleCloudOAuth
(base class for accessing and implementing REST services without authentication)
Depending on the service, you can inherit from one of the 2 classes. The next chapters explain the difference between the 2 classes and the way to implement/use them.
TTMSFNCCloudOAuth
When inheriting from TTMSFNCCloudOAuth
, you’ll be presented with abstract virtual methods that need to be implemented in order to handle the OAuth 2.0 authentication flow. Below are the methods that need to be implemented.
[dcc32 Warning] UDemo.pas(34): W1020 Constructing instance of 'TTMSFNCCloudSample' containing abstract method 'TTMSFNCCustomCloudOAuth.GetAuthenticationURL'
[dcc32 Warning] UDemo.pas(34): W1020 Constructing instance of 'TTMSFNCCloudSample' containing abstract method 'TTMSFNCCustomCloudOAuth.RetrieveAccessToken'
[dcc32 Warning] UDemo.pas(34): W1020 Constructing instance of 'TTMSFNCCloudSample' containing abstract method 'TTMSFNCCustomCloudOAuth.TestTokens'
[dcc32 Warning] UDemo.pas(34): W1020 Constructing instance of 'TTMSFNCCloudSample' containing abstract method 'TTMSFNCCustomCloudOAuth.GetTestTokensResult'
TTMSFNCCloudSample = class(TTMSFNCCloudOAuth)
protected
function GetAuthenticationURL: string; override;
procedure RetrieveAccessToken; override;
public
procedure TestTokens(const ATestTokensRequestResultEvent: TTMSFNCCloudBaseRequestResultEvent = nil); override;
function GetTestTokensResult(const ARequestResult: TTMSFNCCloudBaseRequestResult): Boolean; override;
end;
-
Construct the authentication URL with client-id, secret and callback URL
-
Use the authentication token to convert it to an access token (and optional refresh token)
-
Test the access token against the service and return true when the access token is valid
Applying this on our service implementation:
{ TTMSFNCCloudSample }
function TTMSFNCCloudSample.GetAuthenticationURL: string;
var
url: string;
begin
url := '?redirect_uri=' + TTMSFNCUtils.URLEncode(Authentication.CallBackURL)
+ '&response_type=code'
+ '&client_id=' + Authentication.ClientID;
url := 'https://myservice.com/o/oauth2/auth' + url;
Result := url;
end;
function TTMSFNCCloudSample.GetTestTokensResult(
const ARequestResult: TTMSFNCCloudBaseRequestResult): Boolean;
var
o: TJSONValue;
s: string;
begin
Result := False;
s := ARequestResult.ResultString;
if s <> '' then
begin
o := TTMSFNCUtils.ParseJSON(s);
if Assigned(o) then
begin
Result := not Assigned(TTMSFNCUtils.GetJSONValue(o, 'error'));
o.Free;
end;
end;
end;
procedure TTMSFNCCloudSample.RetrieveAccessToken;
begin
Request.Clear;
Request.Name := 'RETRIEVE ACCESS TOKEN';
Request.Host := 'https://myservice.com';
Request.Path := '/o/oauth2/token';
Request.Query := 'client_id=' + Authentication.ClientID
+ '&client_secret=' + Authentication.Secret
+ '&redirect_uri=' + Authentication.CallBackURL
+ '&code=' + Authentication.AuthenticationToken
+ '&grant_type=authorization_code';
Request.Method := rmPOST;
ExecuteRequest(DoRetrieveAccessToken);
end;
procedure TTMSFNCCloudSample.TestTokens(
const ATestTokensRequestResultEvent: TTMSFNCCloudBaseRequestResultEvent);
begin
Request.Clear;
Request.Name := 'TEST TOKENS';
Request.Host := 'https://www.myservice.com';
Request.Path := '/oauth2/v1/tokeninfo';
Request.Query := 'access_token=' + Authentication.AccessToken;
Request.Method := rmGET;
ExecuteRequest(ATestTokensRequestResultEvent);
end;
Connect
method.
procedure TMyCloudServiceForm.FormCreate(Sender: TObject);
var
c: TTMSFNCCloudSample;
begin
c := TTMSFNCCloudSample.Create;
c.Authentication.ClientID := 'My Client ID';
c.Authentication.Secret := 'My Secret';
c.Authentication.CallBackURL := 'http://localhost:8000';
c.OnConnected := DoConnected;
c.Connect;
end;
procedure TMyCloudServiceForm.DoConnected(Sender: TObject);
begin
TTMSFNCUtils.Log('Connected !');
end;
OnConnected
event is triggered as soon as the service successfully connects via the three-step authentication process. The tokens that are retrieved are automatically saved, and the next time the application runs, the tokens are loaded and the connection process automatically handles this.
After the service implementation is done, and successfully connected, the requests can be made to retrieve information from the service.
TTMSFNCSimpleCloudOAuth
The TTMSFNCSimpleCloudOAuth
is a class that can be used in the same way as the
TTMSFNCCloudOAuth
class but excluding the authentication flow process. You can directly start writing requests to the service you wish to implement. This can, for example, be a file download, or JSON data retrieval, that doesn’t require authentication. Below is a sample that demonstrates this.
procedure TTMSFNCCloudSample.DoRetrieveTestDownloadResult(
const ARequestResult: TTMSFNCCloudBaseRequestResult);
begin
TTMSFNCUtils.Log('File Downloaded !');
end;
procedure TTMSFNCCloudSample.TestDownload;
begin
Request.ClearHeaders;
Request.Host := 'http://www.tmssoftware.net';
Request.Name := 'TEST FILE DOWNLOAD';
Request.Path := '/public/test.zip';
Request.PostData := '';
Request.Method := rmGET;
Request.ResultType := rrtFile;
Request.ResultFile := TTMSFNCUtils.AddBackslash(TTMSFNCUtils.GetDocumentsPath) + 'test.zip';
ExecuteRequest(DoRetrieveTestDownloadResult);
end;
Supported REST methods
The TMS FNC Cloud Pack core implementation supports the following REST methods:
- GET
- POST
- PUT
- PATCH
- UPDATE
- DELETE
Additionally, the PUT and POST methods data can be constructed using a post data builder. This can be combined with multi-part form data if necessary. The sample below is demonstrating a service that requires multi-part form data for uploading a file.
PostDataBuilder.Clear;
PostDataBuilder.AddFormData('userfile', '', True,
ExtractFileName(ARequestResult.DataString), 'application/octet-stream');
s := PostDataBuilder.Build;
Request.Clear;
Request.Name := 'UPLOAD FILE';
Request.Host := Service.BaseURL;
Request.Path := '/upload' + FBasePath + id + '?access_token=' +
Authentication.AccessToken;
Request.Method := rmPUTMULTIPART;
Request.PostData := s;
Request.UploadFile := ARequestResult.DataUpload;
ExecuteRequest(DoRequestUploadFile);
Asynchronous
All requests are handled asynchronously, we wanted to make sure that each action, whether it's retrieving a list of files, or uploading/download a file, is running seamless and doesn't interfere with the main thread. This always makes your application responsive and allows you to perform other tasks while waiting for the download/upload to finish, or the list of files to be loaded.
This also gives the advantage that you can start multiple requests at once, and not having to wait until a specific request has finished. Of course, some requests require additional data that has been retrieved via another request, but we have made the request execution and data retrieval as flexible as possible. Below is a sample that shows the way the request is being made, and how the result is captured.
procedure TRequestForm.DoRequestExecute(const ARequestResult:
TTMSFNCCloudBaseRequestResult);
begin
//File Download Finished
end;
procedure TRequestForm.DownloadFile;
begin
c := SimpleCloudOAuthInstance;
try
c.Request.Clear;
c.Request.Host := 'http://myhost.com';
c.Request.Path := '/download';
c.Request.Query := 'fileid=123';
c.Request.Name := 'Download File';
c.Request.Method := rmGET;
c.ExecuteRequest(DoRequestExecute);
finally
end;
end;
procedure TRequestForm.DownloadFile;
begin
c := SimpleCloudOAuthInstance;
try
c.Request.Clear;
c.Request.Host := 'http://myhost.com';
c.Request.Path := '/download';
c.Request.Query := 'fileid=123';
c.Request.Name := 'Download File';
c.Request.Method := rmGET;
c.ExecuteRequest(
procedure(const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
//File Download Finished
end
);
finally
end;
end;
Utility methods
When writing your own custom service, you can look at the already existing services, that are described in a separate documentation, on how to construct and handle the request. There is already a lot a functionality built-in, such as handling special Unicode characters, converting file to base64, JSON escaping, URL encoding/decoding and many more. The *TMSFNCUtils.pas
unit is available in the TMS FNC Core, which wraps a lot of this functionality.
Sample
To illustrate how to implement your own service, we take the source code from accessing a Google service, such as Google Drive. Google Drive has a common layer in where the authentication flow and access token generation are handled to allow other services from Google implement the API’s on top of this layer.
The first step is to generate the authentication URL.
function TTMSFNCCustomCloudGoogle.GetAuthenticationURL: string;
begin
Result := InitializeAuthenticationURL(Self);
end;
function InitializeAuthenticationURL(const ACloudBase: TTMSFNCCloudOAuth):
string;
var
url, sc: string;
begin
sc := TTMSFNCCloudOAuthOpen(ACloudBase).GetScopes('+', True);
url := '?scope=' + sc
+ '&state=profile'
+ '&redirect_uri='
+ TTMSFNCUtils.URLEncode(ACloudBase.Authentication.CallBackURL)
+ '&response_type=code'
+ '&client_id=' + ACloudBase.Authentication.ClientID
+ '&approval_prompt=force'
+ '&access_type=offline'
+ '&hl=en';
url := 'https://accounts.google.com/o/oauth2/auth' + url;
Result := url;
end;
The URL is a concatenation of The ClientID
, CallBackURL
, some default parameters and a set of scopes, which is crucial to allow the user to identify which services is accessing which information.
For Google Drive, the scopes are added in the constructor:
Scopes.Clear;
Scopes.Add('https://www.googleapis.com/auth/drive');
Scopes.Add('https://www.googleapis.com/auth/drive.file');
Scopes.Add('https://www.googleapis.com/auth/userinfo.profile');
Connect
method, and the Access Token is not yet retrieved, or no longer valid, abrowser is shown which allows identifying and authorizing the application which is requesting access to your files/folders and account information. Below is a screenshot of the browser and the scopes that are requested via the authorization URL.
After Clicking on the “Allow” button, the Application is redirected back to your application which runs an HTTP Server listening to the Callback URL & Port set via Authentication.CallBackURL
. As soon as the HTTP Server catches the OAuth 2.0 redirect callback URL, it parses the URL and generates an authentication token. The next step is to take the authentication token and convert it to an access token:
procedure TTMSFNCCustomCloudGoogle.RetrieveAccessToken;
begin
InitializeRetrieveAccessTokenRequest(Self);
ExecuteRequest({$IFDEF LCLWEBLIB}@{$ENDIF}DoRetrieveAccessToken);
end;
procedure InitializeRetrieveAccessTokenRequest(const ACloudBase:
TTMSFNCCloudOAuth);
begin
ACloudBase.Request.Clear;
ACloudBase.Request.Name := 'RETRIEVE ACCESS TOKEN';
ACloudBase.Request.Host := 'https://accounts.google.com';
ACloudBase.Request.Path := '/o/oauth2/token';
ACloudBase.Request.Query := 'client_id='
+ ACloudBase.Authentication.ClientID
+ '&client_secret=' + ACloudBase.Authentication.Secret
+ '&redirect_uri=' + ACloudBase.Authentication.CallBackURL
+ '&code=' + ACloudBase.Authentication.AuthenticationToken
+ '&grant_type=authorization_code';
ACloudBase.Request.Method := rmPOST;
end;
After retrieving the access token, the service core layer is automatically performing a test to validate the access token and grant access to service API’s. The test needs to be handled by your service implementation. For Google Drive, the test involves calling a simple tokeninfo API endpoint to validate the tokens, but for other services, it could be retrieving the account information, or testing a retrieval of files/folders.
procedure TTMSFNCCustomCloudGoogle.TestTokens(const
ATestTokensRequestResultEvent: TTMSFNCCloudBaseRequestResultEvent = nil);
begin
InitializeTestTokensRequest(Self);
ExecuteRequest(ATestTokensRequestResultEvent);
end;
procedure InitializeTestTokensRequest(const ACloudBase: TTMSFNCCloudOAuth);
begin
ACloudBase.Request.Clear;
ACloudBase.Request.Name := 'TEST TOKENS';
ACloudBase.Request.Host := 'https://www.googleapis.com';
ACloudBase.Request.Path := '/oauth2/v1/tokeninfo';
ACloudBase.Request.Query := 'access_token=' +
ACloudBase.Authentication.AccessToken;
ACloudBase.Request.Method := rmGET;
end;
function TTMSFNCCustomCloudGoogle.GetTestTokensResult(
const ARequestResult: TTMSFNCCloudBaseRequestResult): Boolean;
begin
Result := InitializeTestTokensResult(Self, ARequestResult)
end;
function InitializeTestTokensResult(const ACloudBase: TTMSFNCCloudOAuth;
const ARequestResult: TTMSFNCCloudBaseRequestResult): Boolean;
var
o: TJSONValue;
s: string;
begin
Result := False;
s := ARequestResult.ResultString;
if s <> '' then
begin
o := TTMSFNCUtils.ParseJSON(s);
if Assigned(o) then
begin
Result := not Assigned(TTMSFNCUtils.GetJSONValue(o, 'error'));
o.Free;
end;
end;
end;
Boolean
(true/false). When the result is a true, the service is successfully authenticated and the application can start accessing various API’s
Installing the TMSFNCRESTClientEditor Package
In VCL and FMX you have the option to use the TTMSFNCRESTClientEditor or the full editor for the TTMSFNCRESTClient in design-time.
- Make sure that TMS FNC Core, TMS FNC UI Pack and TMS FNC Cloud pack are installed.
- Locate the correct TMSFNCRESTClientEditorDXE group package for your Delphi version (XE14 = Delphi 11, XE13 = Delphi 10.4, ...)
- Manually install the VCL and FMX packages before you install the Design-Time package (TMSFNCRESTClientEditorPkgDEDXE__).
Now you should be able to see the TTMSFNCRESTClientEditor on your tool-palette.
Resources
Blog Posts
A list of TMS FNC Cloud Pack related blog posts can be found on the TMS Software website.
Videos
A list of TMS FNC Cloud Pack related videos can be found on the TMS Software website.
Terms of use
With the purchase of TMS FNC Cloud Pack, you are entitled to our consulting and support services to integrate the supported cloud services in Delphi applications and with this consulting and support comes the full source code needed to do this integration. As TMS FNC Cloud Pack uses the supported services you are bound to the terms of these services that can be found at:
https://developers.google.com/terms
https://docs.microsoft.com/en-us/legal/microsoft-apis/terms-of-use
https://www.youtube.com/static?template=terms
https://www.paypal.com/webapps/mpp/ua/legalhub-full?country.x=US&locale.x=en_US
https://hubic.com/en/contracts/Contrat_hubiC_2014.pdf
https://stellards.io/Legal/TermsOfService
TMS software is not responsible for the use of TMS FNC Cloud Pack components. The purchase of TMS FNC Cloud Pack does not include any license fee that you might possibly be required to pay tothe supported services. It will depend on your type of usage of these services whether a license fee needs to be paid.It is the sole responsibility of the user or company providing the application that integrates theterms and conditions of the supported services. TMS software does not take any responsibility nor indemnifies any party violating the terms and conditions of the supported services. We cannot guarantee that a 3rd party cloud service will approve or allow the use of the services used in TMS FNC Cloud Pack components in your application(s) now or at any time in the future. This is up to the 3rd party cloud service provider to decide and not under our control. In case the 3rdparty cloud service provider makes changes to the conditions for using the service, the API itself or anything else that causes an incompatibility with our component implementations, tmssoftware.com will do its best to accommodate the changes but cannot be forced in any way or within any timeframe to do so and might be technically limited to do so.
Limited warranty
TMS software cannot guarantee the current or future operation and uptime of the supported services. TMS software offers the consulting and support for TMS FNC Cloud Pack in good faith that the supported services are reliable and future-proof. In no case, TMS software shall offer refunds or any other compensation in case the supported services terms/operation changes or stops.