C++ SDK for Amazon Web Services (AWS) tutorial
One can really appreciate modern C++ programs written from scratch, which do not have backward compatibility problems and strange architecture solutions, commonly found in the past. This article does not focus on documentation, it rather pays attention to key aspects which determine C++ SDK behaviour.
С++11
All the libraries and applications which are not written in C++11 are obsolete nowadays. I feel sorry for the developers who, in the attempt to increase their audience, try to do without C++11 creating libraries. Amazon is well aware of the fact that such libraries and applications are a thing of the past and that is why all C++11 features, such as auto, smart pointer and lambda are embedded. Being able to use Lambda as a call-back function is essential, and another pleasant bonus is that the product doesn’t have explicit new/delete language constructs.
Code Simplicity
As a result, let us take a look at the code which we get. We will place key value pair into DynamoDB:
DynamoDBClient client;
AttributeValue haskKeyAttribute;
hashKeyAttribute.SetS(“SampleHashKeyValue”)
AttributeValue valueAttribute;
valueAttribute.SetS(“SampleValue”)
PutItemRequest putItemRequest;
putItemRequest.WithTableName(“TestTableName”).AddItem(“HashKey”, hashKeyAttribute).AddItem(“Value”, valueAttribute);
client.PutItem(putItemRequest);
Taking this into consideration, who can say that C++ is more complicated than Java or Python? Moreover, it takes up less memory and the overall performance is faster.
There are no Unnecessary Dependencies
Developers from Amazon understand that every unnecessary dependency causes additional difficulties at the stage of project build and assembly, and consequently decreases the number of potential users. That is why AWS C++ SDK does not depend on boost or any other fundamental frameworks. It does not contain even small libraries, e.g. logging library. The only dependency, which is used, is HTTP client. You can either choose between system CURL, WinHTTP, WinInet, or come up with your own implementations.
CMake
С++ is moving towards standardization of project description. The best solution so far is CMake, which enables assembly on a varied range of platforms and compilers. That is why Amazon uses CMake. It is very handy to work in CLion.
Dependency Injection
The basis for application configuration is dependency injection. We can either use default implementations developed by Amazon or create our own implementations for http-client, logging, authorization, memory allocator, rate limiting and repeated attempts strategy, asynchronous event handler, etc. Each component is small, can be easily tested, and does not cause problems in the process of integration.
Logging
There is no logging library in the dependencies. If you want to receive logs, you need to implement a certain interface and transfer it to configuration in the course of client initialization. Then you will receive callback calls with text logs and you can write them wherever you want. In the default implementation, everything is written into logs in a current folder and old logs are deleted every hour.
Synchronous and Asynchronous Versions of all Operations
As application architecture can be different, all the operations have both synchronous and asynchronous variants. In the synchronous variant, you wait for the operation to finish (it can be quite long if you are uploading a large file), and then you verify the back function:
CreateTableOutcome createTableOutcome = dynamoDbClient->CreateTable(createTableRequest);
if (createTableOutcome.IsSuccess())
{
…
} else {
…
}
In the asynchronous variant, you set the callback function, which is invoked when the operation is completed. The call back function receives information on query data, an answer to the query and some additional context, which can be set before the call to understand later what kind of a call it is, and how its result can be processed.
void putItemFinished(const DynamoDBClient *client, const PutItemRequest& request,
const PutItemOutcome& outcome,
const std::shared_ptr<AsyncContext>& context)
{
if (outcome.IsSuccess())
{
SEND_QUEUE.erase(context->GetUUID());
}
}
auto context = Aws::MakeShared<AsyncContext>(“Hello!”);
context.SetUUID(“UniqueRequestKey”);
SEND_QUEUE[“UniqueRequestKey”] = putItemRequest;
client.PutItemAsync(putItemRequest, &putItemFinished, context);
Another advantage of C++11 is that one can transmit not only function, but also a class method of a certain object (via std::bind) or lambda as callback.
Asynchronous Executor Support
If you like asynchronous operations and your program contains background-thread pool and class performance of asynchronous operations, you can use it to launch AWS C++ SDK operations. This way, all asynchronous operations in your application are performed on the basis of one scheme/scenario and you save resources on the background thread, which otherwise would have been launched by SDK.
Rate Limiting
If necessary, you can limit the rate of data transfer for some operations. To get full control of data transmission band, implement RateLimiter interface and transfer this implementation into configuration.
No Exceptions
The question of using/not using exceptions in C++ has been discussed for a long time. Recently more and more developers have been trying to avoid using exceptions. AWS C++ SDK does not have exceptions. Its creators say that this accounts for higher flexibility and performance. If you need to find out error code, you need to check outcome.IsSuccess(). If outcome has false value, there will be additional data on the error. This approach is handy.
Strategy of Repeated Attempts of the Operation is Enabled by Default
As every SDK created by Amazon depends on network operations, users should realize that network operations quite often result in errors. Sometimes there is no Wi-Fi, sometimes there is no mobile connection and sometimes a relatively reliable wired channel fails to download a 3-terabyte file. AWS C++ SDK is by default trying to repeat the operation, which failed. Algorithm details (the number of attempts, time span between attempts) can be controlled with one’s own repeated attempts strategy.
The Ability to Define Memory Allocators
If such factors as the amount of memory used by the application, the time and speed of its allocation and removal are essential for you (it should be essential for you if you write in C++), you can define your own memory allocator. You need to inherit methods/properties from MemorySystemInterface and define several methods. You can try ‘borrowing’ a good allocator and adjusting it to your amount of data and algorithms; it will guarantee a decent increase in performance.
GitHub
Everything is placed on GitHub; Issues, Pull Requests are accepted. Contact with community is well established.
Good luck using AWS from C++ applications!