smaws-clients
is composed of generated Amazon Web Services (AWS) service SDKs for OCaml from Smithy definitions.
The underlying SDKs use EIO for its concurrency model, taking advantage of the OCaml 5.0 Effects support, that enables a cleaner and simpler concurrency syntax without monadic support (like lwt).
This project is very much a work in progress. The current focus is on generating correct and useful SDKs for core AWS services like STS, SQS, S3, DynamoDB, etc. rather than support for every AWS service.
It should be treated as a preview, as it lacks a number of important features that are needed for production use.
Use opam to install smaws-clients:
opam install smaws-clients
smaws-clients
exposes all of the service SDKs. It works with smaws-lib
for authentication and protocol implementations.
Service SDKs are organised under its own module with the naming convention Smaws_Clients.*
e.g. Smaws_Clients.DynamoDB
.
Types for all operations and their components are found directly under the service module.
Builder functions, in the form of `make_<type_name>`, also exist directly in the service module. They're particularly helpful with larger types that have a lot of optional fields.
Service Operations exist in a submodule of a Service SDK e.g. SQS ListQueues is in the Smaws_Clients.SQS.ListQueues
module. (You can find all the operations available for a particular service on the Actions page of the corresponding API Reference section of the AWS documentation for that service).
Calling a service operation consists of:
~/.aws/credentials
file (non-SSO). It does not support authentication methods suitable for use on EC2/ECS/Lambda such as EC2/ECS Metadata Secret retrieval. SSO authentication retrieval is not currently supported.A configuration object is used by the context to determine authorization and other environment settings (such as the region to use).
open Smaws_Lib
(* Initialise with defaults from environment *)
let config = Config.defaultConfig ()
(* Customise the config object *)
let config = Config.make
~resolveRegion: (fun () -> "us-west-1")
~resolveAuth: (Auth.fromProfile env)
()
In the above example:
~resolveRegion:
the region is hardcoded (us-west-1
)~resolveAuth:
the authorization details are retrieved from the current AWS profile set in the environment (more details on authorization below).In the configuration object, an authorization resolver (from the ~resolveAuth
parameter) determines how your AWS credentials are retrieved and used.
Auth.fromEnvironment ()
looks for your credentials in the environment variables AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
and (if specified) AWS_SESSION_TOKEN
.
This can be useful for ephemeral cases where you have retrieved a set of credentials (e.g. from a role assumption), but defining and exporting AWS credentials in your environment over long periods (such as in shell scripts) is bad practice and more likely to lead to credential leakage.
Auth.fromProfile ()
takes the name of your current profile (specified by the AWS_PROFILE
environment variable) and loads your credentials from $HOME/.aws/config
and/or $HOME/.aws/credentials
. If a profile name is not specified in AWS_PROFILE
, the profile with name default
is used.
NOTE: this method only supports profiles stored with aws_access_key_id
/aws_secret_access_key
at the moment.
This is suitable for local validation, but storing long-lived IAM access keys with broad permissions this way is considered to be poor security practice. We recommend provisioning IAM access keys with narrow permissions and a short expiry time for testing and validation. In the future, we'll support AWS SSO cached credentials for secure access retrieval.
Not currently supported.
Not currently supported.
Calling a service operation first requires you to create a context object. The context ties together a configuration and an eio switch for calling service operations.
NOTE: it isn't possible to use this library with other effect-based concurrency frameworks like miou or riot, or older concurrency frameorks like lwt or async, without an eio compatibility shim (these are untested).
The HTTP client bound to the context creates a shared connection pool for each service endpoint. That connection pool is bound to the lifetime of the switch.
You can share the context object between services or create separate ones (as required).
open Smaws_Lib
let _
Eio_main.run (fun env ->
Eio.Switch.run (fun sw ->
let config = Config.defaultConfig () in
let ctx = Context.make ~config ~sw in
...
The above example is typical of a command line utility, where you initialise the switch as part of your main programme. Long running servers or frameworks may already provide you with an eio switch.
Service modules each have their own module under Smaws_Clients
. We recommend using local opens because each service module contains numerous types, associated builder functions and operations, which may clutter your namespace.
let read_table_entries =
let open Smaws_Clients.DynamoDB in
...
An operation request is constructed with the corresponding make_<operation>_<name>
convenience function, or you can also use the generated <operation_name>_input
type directly).
let read_table_entries context =
let open Smaws_Clients.DynamoDB in
let request = make_list_tables_request ~table_name:"orders" () in
...
You can then invoke an operation using its submodule's request
function:
let result = ListTables.request context request
These return a result type. We recommend binding the let+
operator to Result.bind
so you can cascade multiple results as needed.
let (let+) r b = Result.bind r b
Errors are defined as polymorphic variant types to make error handling more ergonomic, and to allow different layers (HTTP, protocol, operation) to define what errors they can throw. Each class of error is documented below.
Errors specifically returned from operations are individually in the operation definition. For example:
module PutItem = sig
val request :
Context.t ->
put_item_input ->
( put_item_output,
[> `AWSServiceError of AwsErrors.aws_service_error
| `ConditionalCheckFailedException of
conditional_check_failed_exception
| `HttpError of Http.http_failure
| `InternalServerError of internal_server_error
| `InvalidEndpointException of invalid_endpoint_exception
| `ItemCollectionSizeLimitExceededException of
item_collection_size_limit_exceeded_exception
| `JsonParseError of
Json.DeserializeHelpers.jsonParseError
| `ProvisionedThroughputExceededException of
provisioned_throughput_exceeded_exception
| `RequestLimitExceeded of request_limit_exceeded
| `ResourceNotFoundException of
resource_not_found_exception
| `TransactionConflictException of
transaction_conflict_exception ] )
result
end
They can be patterned matched, e.g.
(* Write an item to the table if it does not exist. Returns the item if it is written, otherwise None *)
let insert_item =
...
let request = make_put_item_request ~item ~condition_expression in
let put_item_response = PutItem.request ctx request in
match put_item_response with
| Ok result -> Some (map_attributes_to_item result.attributes)
(* Catch condition check failure, which indicates our condition failed so
we did not want to write this item
*)
| Error (`ConditionalCheckFailedException _) -> None
(* Raise any other errors as exceptions *)
| Error e -> raise (InsertItemError e)
As can be seen in the above example, some operations list out quite a number of error conditions (most of which are not relevant). In other cases, some errors will be missing from the operation specification: Smithy definitions are often incomplete or contain errors or inconsistencies between services.
If an operation returns an error not specified in its definition, it will be wrapped up as an `AWSServiceError type. You can match these by their name (and/or namespace) as a string:
match item_response with
| Error (`AWSServiceError e) when e._type.name = "SomeError" -> (* special handling *)
All HTTP errors are packaged as `HttpError, which can be processed if you need to implement retries (there is no builtin retry support).
All service SDKs that are built are listed below.
Please note inline documentation from the Smithy definitions is not available at this time.
Smaws_Clients.ACM
ACM client library built on EIO.Smaws_Clients.AppRunner
AppRunner client library built on EIO.Smaws_Clients.BackupGateway
Backup Gateway client library built on EIO.Smaws_Clients.CloudTrail
CloudTrail client library built on EIO.Smaws_Clients.CodeConnections
CodeConnections client library built on EIO.Smaws_Clients.CognitoIdentity
Cognito Identity client library built on EIO.Smaws_Clients.ConfigService
Config Service client library built on EIO.Smaws_Clients.DAX
DAX client library built on EIO.Smaws_Clients.DirectoryService
Directory Service client library built on EIO.Smaws_Clients.DynamoDB
DynamoDB client library built on EIO.Smaws_Clients.DynamoDBStreams
DynamoDB Streams client library built on EIO.Smaws_Clients.EventBridge
EventBridge client library built on EIO.Smaws_Clients.FMS
FMS client library built on EIO.Smaws_Clients.Kendra
kendra client library built on EIO.Smaws_Clients.Keyspaces
Keyspaces client library built on EIO.Smaws_Clients.Kinesis
Kinesis client library built on EIO.Smaws_Clients.KinesisAnalytics
Kinesis Analytics client library built on EIO.Smaws_Clients.KinesisAnalyticsV2
Kinesis Analytics V2 client library built on EIO.Smaws_Clients.KMS
KMS client library built on EIO.Smaws_Clients.Lightsail
Lightsail client library built on EIO.Smaws_Clients.MarketplaceAgreement
Marketplace Agreement client library built on EIO.Smaws_Clients.MigrationHub
Migration Hub client library built on EIO.Smaws_Clients.OpenSearchServerless
OpenSearchServerless client library built on EIO.Smaws_Clients.PI
PI client library built on EIO.Smaws_Clients.Proton
Proton client library built on EIO.Smaws_Clients.ResourceGroupsTaggingAPI
Resource Groups Tagging API client library built on EIO.Smaws_Clients.Route53RecoveryCluster
Route53 Recovery Cluster client library built on EIO.Smaws_Clients.ServiceDiscovery
ServiceDiscovery client library built on EIO.Smaws_Clients.SFN
SFN client library built on EIO.Smaws_Clients.Shield
Shield client library built on EIO.Smaws_Clients.Snowball
Snowball client library built on EIO.Smaws_Clients.SQS
SQS client library built on EIO.Smaws_Clients.SSM
SSM client library built on EIO.Smaws_Clients.SWF
SWF client library built on EIO.Smaws_Clients.Transcribe
Transcribe client library built on EIO.Smaws_Clients.WAF
WAF client library built on EIO.Smaws_Clients.WAFV2
WAFV2 client library built on EIO.Smaws_Clients.WorkMail
WorkMail client library built on EIO.