Awesome
AWS SDK for Delphi
The AWS SDK for Delphi enables Delphi developers to easily work with Amazon Web Services and build scalable solutions with Amazon SES, Amazon SQS, and more. It is a non-official SDK based on the official AWS SDK for .NET. Sample projects can be found in AWS SDK for Delphi Samples repository.
Supported services
This is the list of AWS services currently supported by the SDK. More will be added over time:
- Amazon Lex: Conversational AI for Chatbox
- Amazon Polly: Text To Speech
- Amazon Rekognition: Image and Video Analysis
- Amazon S3: Simple Storage Service
- Amazon SES: Simple Email Service API (Classic)
- Amazon SES V2: Simple Email Service API v2
- Amazon SNS: Simple Notification Service
- Amazon SQS: Simple Queue Service
- Amazon Translate: Text Translation
Bug report and feature requests
Please use the GitHub Issues page to report problems or request features.
Supported Delphi versions and platforms
AWS SDK for Delphi supports all recent Delphi versions since Delphi 10.3 Rio (i.e., Delphi 10.4 Sydney, Delphi 11, Delphi 12, etc.) and supports all platforms available in those Delphi versions: Windows, Linux, Android, iOS and macOS.
Required libraries
AWS SDK for Delphi does not require any 3rd party library, it's written in 100% native Delphi code and works on all SKUs of supported Delphi versions.
Installation
You can install the library performing a manuall installation.
Manual installation
For each different platform you want to install the SDK:
- Open
AWSPackages.groupproj
project group in your Delphi IDE. - Add the platform output folder to the Delphi platform library path. For example, if you are building for Delphi 12, Win32, add the
<sdk_folder>/packages/d12/Win32/Release
folder to Delphi 12, Win32 library path. - Build all packages for the platform you want to install, in Release mode.
Using the SDK
Each Amazon web service has its own package and unit name scheme, which is AWS<service>.dproj
and AWS.<service>.*.pas
, respectively. For example, for Amazon SQS (Simple Queue Service), the package name is AWSSQS.dproj
and unit name is AWS.SQS.pas
(and all other units in the package follow same pattern, like AWS.SQS.Client.pas
or AWS.SQS.ClientIntf.pas
.
Most types you need will be in the main unit, which for example is AWS.SQS
. So that's the only unit you will need to use most of the functions. From there you can access all the available API operations. Each operation method receives a request interface and returns a response interface.
In summary, this is the process to perform API requests:
- Use the main unit of the service, e.g.
AWS.SQS
; - Instantiate the client interface (
TAmazonSQSClient
); - Create and fill the request;
- Call operation method passing the request to receive the response;
- Process the response.
The following examples receive a message from an SQS queue and output the id and body of each message received:
// 1. Use main unit
uses AWS.SQS;
procedure WriteMessageIds(const QueueUrl: string);
var
Client: IAmazonSQS;
Response: IReceiveMessageResponse;
Request: IReceiveMessageRequest;
Msg: AWS.SQS.TMessage;
begin
// 2. Instantiate client interface
Client := TAmazonSQSClient.Create;
// 3. Create and fill the request
Request := TReceiveMessageRequest.Create;
Request.QueueUrl := QueueUrl;
// 4. Call operation method passing the request to receive the response;
Response := Client.ReceiveMessage(Request);
// 5. Process the response
for Msg in Response.Messages do
begin
WriteLn(Msg.MessageId);
WriteLn(Msg.Body);
WriteLn;
end;
end;
The following example sends an e-mail to the specified address using the specified subject and message:
// 1. Use main unit
uses AWS.SES;
procedure SendEmail(const Recipient, Subject, Content: string);
var
Client: IAmazonSimpleEmailService;
Request: ISendEmailRequest;
Response: ISendEmailResponse;
begin
// 2. Instantiate client interface
Client := TAmazonSimpleEmailServiceClient.Create;
// 3. Create and fill the request
Request := TSendEmailRequest.Create;
Request.Source := SenderEmail;
Request.Destination := TDestination.Create;
Request.Destination.ToAddresses.Add(Recipient);
Request.Message := TMessage.Create(
TContent.Create(Subject),
TBody.Create(TContent.Create(Content)));
// 4. Call operation method passing the request to receive the response;
Response := Client.SendEmail(Request);
// 5. Process the response
WriteLn(Response.MessageId);
end;
In all request objects, lists and dictionaries are already instantiated, while other associated objects are not. You don't need to destroy any interface or object passed to or received from the operations, or added to requests. Some operations have overloaded methods that receive fewer raw parameters instead of the full request object, for simpler usage.
For more information about the available operations, please refer to the API documentation of the Amazon service you are trying to use. Or, of course, use Delphi code completion to find all the methods available in each service client.
Examples for specific services
Amazon SNS
You can fully use Amazon SNS: Simple Notification Service from AWS SDK for Delphi. Main unit is AWS.SNS
. You find find more detailed information in this article about using Amazon SNS with AWS SDK for Delphi, and of course you can refer to Amazon SNS API reference itself.
Creating the client:
var
Client: IAmazonSimpleNotificationService;
begin
Client := TAmazonSimpleNotificationServiceClient.Create;
end;
Get ARN for all existing topics:
function GetAllTopics(AllTopics: TList<string>);
var
ListRequest: IListTopicsRequest;
ListResponse: IListTopicsResponse;
Topic: TTopic;
begin
ListRequest := TListTopicsRequest.Create;
repeat
ListResponse := Client.ListTopics(ListRequest);
for Topic in ListResponse.Topics do
AllTopics.Add(Topic.TopicArn);
ListRequest.NextToken := ListResponse.NextToken;
until ListRequest.NextToken = '';
end;
Create a topic, get its ARN, set/get its attributes, and delete topic:
var
Response: ICreateTopicResponse;
TopicArn: string;
SetAttrRequest: ISetTopicAttributesRequest;
GetAttrResponse: IGetTopicAttributesResponse;
begin
// create new topic and get ARN
Response := Client.CreateTopic('test-name');
TopicArn := Response.TopicArn;
// set topic attribute
SetAttrRequest := TSetTopicAttributesRequest.Create(TopicArn, 'DisplayName', 'My topic');
Client.SetTopicAttributes(SetAttrRequest);
// verify topic attributes
GetAttrResponse := Client.GetTopicAttributes(TopicArn);
DisplayName := GetAttrResponse.Attributes['DisplayName']);
// delete new topic
Client.DeleteTopic(TopicArn);
end;
Subscribe a topic to an SQS queue via queue URL, adding the proper permissions:
function SubscribeQueue(Client: IAmazonSimpleNotificationService;
const TopicArn: string; SQSClient: IAmazonSQS; const SQSQueueUrl: string): string;
var
GetAttrResponse: IGetQueueAttributesResponse;
GetAttrRequest: IGetQueueAttributesRequest;
SQSQueueArn: string;
Policy: TPolicy;
PolicyStr: string;
TopicArn: string;
SetAttrRequest: ISetQueueAttributesRequest;
begin
// Get the queue's existing policy and ARN
GetAttrRequest := TGetQueueAttributesRequest.Create;
GetAttrRequest.QueueUrl := SQSQueueUrl;
GetAttrRequest.AttributeNames.Add(TSQSConsts.ATTRIBUTE_ALL);
GetAttrResponse := SQSClient.GetQueueAttributes(GetAttrRequest);
SQSQueueArn := GetAttrResponse.Attributes['QueueArn'];
if GetAttrResponse.Attributes.TryGetValue('Policy', PolicyStr) then
Policy := TPolicy.FromJson(PolicyStr)
else
Policy := TPolicy.Create;
try
SetLength(Result, 0);
if not HasSQSPermission(Policy, TopicArn, SQSQueueArn) then
AddSQSPermission(Policy, TopicArn, SQSQueueArn);
Result := Client.Subscribe(TopicArn, 'sqs', SQSQueueArn).SubscriptionArn;
SetAttrRequest := TSetQueueAttributesRequest.Create;
SetAttrRequest.QueueUrl := SQSQueueUrl;
SetAttrRequest.Attributes.Add('Policy', Policy.ToJson);
SQSClient.SetQueueAttributes(SetAttrRequest);
finally
Policy.Free;
end;
end;
Subscribe a topic to e-mail and return the subscription ARN:
function SubscribeTopic(const TopicArn, EmailAddress: string): string;
var
Latest: TDateTime;
Response: IListSubscriptionsByTopicResponse;
begin
// subscribe an email address to the topic
Client.Subscribe(TSubscribeRequest.Create(TopicArn, 'email', EmailAddress));
// wait until subscription has been confirmed, wait time for two minutes
Latest := IncMinute(Now, 2);
while Now < Latest do
begin
// get subscriptions for topic
Response := Client.ListSubscriptionsByTopic(TopicArn);
// test whether the subscription has been confirmed
if Response.Subscriptions[0].SubscriptionArn <> 'PendingConfirmation' then
Exit(Response.Subscriptions[0].SubscriptionArn);
// wait
Sleep(15 * 1000);
end;
end;
Publish a message to a topic:
// publish a message to the topic
Client.Publish(TPublishRequest.Create(TopicArn, 'Test message', 'Subject'));
Delete a subscription:
// delete the subscription
Client.Unsubscribe(SubArn);
Parse an SNS message from JSON and validate signature:
function GetMessage(const Json: string): AWS.SNS.Message.TMessage;
begin
Result := AWS.SNS.Message.TMessage.ParseMessage(Json);
if not Result.IsMessageSignatureValid then
raise Exception.Create('Invalid message: bad signature');
end;
Send an SMS message to a phone number:
var
Client: IAmazonSimpleNotificationService;
Request: IPublishRequest;
begin
Client := TAmazonSimpleNotificationServiceClient.Create;
Request := TPublishRequest.Create;
Request.PhoneNumber := '+184298765321';
Request.Message := 'Hello from AWS SDK for Delphi!';
Client.Publish(Request);
end;
Credentials
The AWS SDK for Delphi searches for credentials in a certain order and uses the first available set for the current application.
Credential search order
- Credentials that are explicitly set on the AWS service client, as described in Passing access and secret keys directly to client.
- A credentials profile with the name specified by a value in
TAWSConfigs.AWSProfileName
. - A credentials profile with the name specified by the
AWS_PROFILE
environment variable. - The [default] credentials profile.
Profile resolution
The TAWSConfigs.AWSProfilesLocation
property controls how the AWS SDK for Delphi finds credential profiles. If it's empty, it searches the shared AWS credentials file in the default location. If the profile isn't there, search ~/.aws/config
(Linux or macOS) or %USERPROFILE%\.aws\config
(Windows). If TAWSConfigs.AWSProfilesLocation
contains the path to a file in the AWS credentials file format, then the SDK searches for credentials only in the specified file for a profile with the specified name.
Please refer to AWS documentation for more information about credentials file settings and named profiles.
Passing access and secret keys directly to client
You can simply pass the Access key ID and Secret key directly in the client constructor:
Client := TAmazonSQSClient.Create(myAccessKey, mySecretKey);
Although using credentials profile is recommended as it's easier to manage and also compatible with AWS Command Line Interface.
Tests
Important: Do not run the integration tests on a production account.
Integration tests can be found in the AWSTests project. These tests assume that a default profile has been configured for credentials. You can set up credentials using Configuration files, Named profiles or Environment variables.
The tests are designed to create and delete the resources needed for testing but it is important to keep your data safe. Do not run these tests on accounts that contain production data or resources. Since AWS resources are created and deleted during the running of these tests, charges can occur. To reduce charges occurred by running the tests focus on AWS resources that have minimal cost.
Credits
Some OpenSSL internal classes were inspired from the Delphi-OpenSSL repository: https://github.com/lminuti/Delphi-OpenSSL.
Unit AWS.Json.Helpers
is based on Uwe Raabe's REST-Json-Helpers: https://github.com/UweRaabe/REST-JSon-Helpers.
License
AWS SDK for Delphi is fair-code distributed under Apache 2.0 with Commons Clause license.