<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Soto</title><description>Swift SDK for AWS.</description><link>https://soto.codes</link><language>en</language><lastBuildDate>Sun, 27 Oct 2024 10:48:33 +0000</lastBuildDate><pubDate>Sun, 27 Oct 2024 10:48:33 +0000</pubDate><ttl>1440</ttl><atom:link href="https://soto.codes/feed.xml" rel="self" type="application/rss+xml"/><item><guid>https://soto.codes/2024/07/v7-release.html</guid><link>https://soto.codes/2024/07/v7-release.html</link><title>Soto v7.0.0</title><description>We are really pleased to announce the release of version 7 of Soto.We have replaced the internals of Soto. All the SwiftNIO EventLoopFuture based code has been replaced with Swift concurrency. The advantage of this includeThis does come with one major change to the APIs. Along with the removal of the EventLoop based internal code the EventLoopFuture based APIs have been removed. From this point on Soto will only supply Swift concurrency APIs.Middleware has been re-written to support a Middleware stack…</description><pubDate>Mon, 8 Jul 2024 15:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="soto_v7_0_0">Soto v7.0.0</h1><p>We are really pleased to announce the release of version 7 of Soto.</p><h2 id="swift_concurrency">Swift Concurrency</h2><p>We have replaced the internals of Soto. All the SwiftNIO EventLoopFuture based code has been replaced with Swift concurrency. The advantage of this include</p><ul><li>An easier to read and maintain code base</li><li>A cleaner API surface</li><li>Better support for streaming of requests and responses</li><li>Additional features we weren't able to implement previously (like Event streams)</li></ul><p>This does come with one major change to the APIs. Along with the removal of the EventLoop based internal code the EventLoopFuture based APIs have been removed. From this point on Soto will only supply Swift concurrency APIs.</p><h2 id="middleware">Middleware</h2><p>Middleware has been re-written to support a Middleware stack result builder. Many of the processes Soto applies to a request have been converted into middleware and when we construct our client and services we build a middleware stack of these eg</p><pre><code><span class="swift-keyword">self</span>.<span class="swift-property">middleware</span> = <span class="swift-type">AWSMiddlewareStack</span> {
    <span class="swift-type">SigningMiddleware</span>(credentialProvider: credentialProvider)
    <span class="swift-type">RetryMiddleware</span>(retryPolicy: retryPolicyFactory.<span class="swift-property">retryPolicy</span>)
    <span class="swift-type">ErrorHandlingMiddleware</span>(options: options)
}</code></pre><p>Much of this is internal and isn't visible to the user but if you want to add multiple middleware to your client you will need to use the middleware stack result builder to pass them to the client.</p><h2 id="full_details">Full details</h2><p>You can get the full details of all the changes in the <a href="https://github.com/soto-project/soto/releases/7.0.0">release notes</a>.</p>]]></content:encoded></item><item><guid>https://soto.codes/2023/08/v7-alpha-release.html</guid><link>https://soto.codes/2023/08/v7-alpha-release.html</link><title>Soto Version 7 Alpha</title><description>An alpha for Soto version 7.0 has just been released. This version has some API improvements and considerable internal changes. Below is listed some of the more major changes and how they affect the library and its users.The library is now completely written using Swift concurrency. The &lt;code&gt;EventLoopFuture&lt;/code&gt; based internals are gone along with the &lt;code&gt;EventLoopFuture&lt;/code&gt; APIs. This allows us to make full use of all the features of Swift concurrency and also use the new Swift concurrency based…</description><pubDate>Thu, 10 Aug 2023 14:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="soto_version_7_alpha">Soto Version 7 Alpha</h1><p>An alpha for Soto version 7.0 has just been released. This version has some API improvements and considerable internal changes. Below is listed some of the more major changes and how they affect the library and its users.</p><h2 id="swift_concurrency">Swift Concurrency</h2><p>The library is now completely written using Swift concurrency. The <code>EventLoopFuture</code> based internals are gone along with the <code>EventLoopFuture</code> APIs. This allows us to make full use of all the features of Swift concurrency and also use the new Swift concurrency based APIs from AsyncHTTPClient which have better support for streamed response payloads.</p><h3 id="streamed_payloads">Streamed Payloads</h3><p>Operations that returned streamed responses, instead of returning the payload by repeated calling a closure now return the streamed payload as an <code>AWSHTTPBody</code> which conforms to a <code>AsyncSequence</code> of <code>ByteBuffers</code>. You can extract the payload using the pattern below or alternatively use the function <code>AWSHTTPBody.collect(upTo:)</code> to collate the stream of buffers into one.</p><pre><code><span class="swift-keyword">let</span> result = <span class="swift-keyword">try await</span> <span class="swift-type">S3</span>.<span class="swift-call">getObject</span>(.<span class="swift-keyword">init</span>(bucket: <span class="swift-string">"MyBucket"</span>, key: <span class="swift-string">"name"</span>))
<span class="swift-keyword">for try await</span> buffer <span class="swift-keyword">in</span> result.<span class="swift-property">body</span> {
    <span class="swift-call">processBuffer</span>(buffer)
}</code></pre><h3 id="event_streams">Event streams</h3><p>Event stream APIs have previous been difficult to implement. <code>S3.SelectObjectContent</code> had a custom implementation, but other operations that received an event stream did not work. The move to <code>AsyncSequence</code> based payloads has simplified implementing these and now there is a generic solution for them all. This solution has been tested on <code>S3.SelectObjectContent</code> and <code>Lambda.InvokeWithResponseStream</code>. The stream of events are accessed from an <code>AWSEventStream</code> which conforms to <code>AsyncSequence</code>. At this point in time there is no support for sending event streams.</p><h2 id="request_encoding_response_decoding">Request encoding/Response decoding</h2><p>The solution for encoding of request header, query values etc and decoding of response header values has always been unsatisfactory. When encoding a request's headers Soto would use <code>Mirror</code> to extract the values out of the input shape. When decoding response headers the header values were added to the input to the Codable decoders, which meant the input had to be in a form the values could be added. JSON reponses had to be decoded to a dictionary before header values were added to the dictionary.</p><p>Both of these have been improved by passing a container to the encode/decode functions (via userInfo) which holds the request/response details. The encode functions use their request container to update the request headers, query parameters. The decode functions use their response container to extract header values.</p><p>These changes give us performance improvements at both the encoding and decoding stages. We aren't using <code>Mirror</code> while encoding, instead we are writing the values directly to the headers/query arrays during the <code>encode(to:)</code> functions. Decoding of JSON files doesn't require us use our custom DictionaryDecoder. Instead we can use the most up to date <code>JSONDecoder</code> which is considerably faster.</p><h2 id="middleware">Middleware</h2><p>Previously Soto middleware provided you with a chance to edit the request before it was sent or the response just after receiving it. This has changed structure to allow more flexibility. You are provided with the request, and a closure to call the next middleware and are expected to return either the response from the closure or an edited version of it. Below is an example middleware.</p><pre><code><span class="swift-keyword">struct</span> MyMiddleware: <span class="swift-type">AWSMiddlewareProtocol</span> {
    <span class="swift-keyword">func</span> handle(<span class="swift-keyword">_</span> request: <span class="swift-type">AWSHTTPRequest</span>, context: <span class="swift-type">AWSMiddlewareContext</span>, next: <span class="swift-type">AWSMiddlewareNextHandler</span>) <span class="swift-keyword">async throws</span> -&gt; <span class="swift-type">AWSHTTPResponse</span> {
        <span class="swift-keyword">let</span> request = <span class="swift-call">processRequest</span>(request)
        <span class="swift-keyword">let</span> response = <span class="swift-keyword">try await</span> <span class="swift-call">next</span>(request, context)
        <span class="swift-keyword">return</span> <span class="swift-call">processResponse</span>(response)
    }
}</code></pre><p>This middleware is only editing requests and responses but there is nothing stopping you doing something more complex. In actual fact the middleware is flexible enough now that every part of the Soto request/response processing (signing, error handling, retries, endpoint discovery) is now done with middleware.</p><h3 id="middleware_stack">Middleware Stack</h3><p>We also use a result builder to build the middleware stack. When you provide middleware to <code>AWSClient</code> or your service it can be either as an individual middleware or a stack of middleware.</p><pre><code><span class="swift-keyword">let</span> client = <span class="swift-type">AWSClient</span>(
    middleware: <span class="swift-type">AWSMiddlewareStack</span> {
        <span class="swift-type">AWSLoggingMiddleware</span>()
        <span class="swift-type">MyMiddleware</span>()
    }
)</code></pre><h2 id="sotocrypto_removed">SotoCrypto removed</h2><p>The library now has platform requirements of macOS v10.15 and iOS v13. Because of this we can now use the <code>swift-crypto</code> package on all platforms and can get rid of the platform check in the <code>Package.swift</code>. This will fix the issues when cross compiling for Linux on macOS where it would not include <code>swift-crypto</code>. Also it means there is one less package to maintain.</p>]]></content:encoded></item><item><guid>https://soto.codes/2022/12/build-plugin-experiments.html</guid><link>https://soto.codes/2022/12/build-plugin-experiments.html</link><title>Soto and Swift Build Plugins</title><description>Swift 5.6 introduced a new Swift Package Manager feature: build tool plugins. These allows custom tools to be invoked during the build process. They are primarily used for generating Swift source code from another source.AWS define the APIs for all their services using the &lt;a href="https://smithy.io"&gt;Smithy&lt;/a&gt; interface design language (IDL). The majority of Soto is generated code built from these model files. The &lt;a href="https://github.com/soto-project/soto-codegenerator"&gt;SotoCodeGenerator&lt;/a&gt; project…</description><pubDate>Tue, 6 Dec 2022 11:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="soto_and_swift_build_plugins">Soto and Swift Build Plugins</h1><div class="article-update">

Since writing this post the SotoCodeGenerator build plugin has had an official release. You can find out more about using it in the <a href="https://github.com/soto-project/soto-codegenerator/blob/main/README.md">README</a> for the SotoCodeGenerator GitHub repository.

</div><p>Swift 5.6 introduced a new Swift Package Manager feature: build tool plugins. These allows custom tools to be invoked during the build process. They are primarily used for generating Swift source code from another source.</p><p>AWS define the APIs for all their services using the <a href="https://smithy.io">Smithy</a> interface design language (IDL). The majority of Soto is generated code built from these model files. The <a href="https://github.com/soto-project/soto-codegenerator">SotoCodeGenerator</a> project is used to build the Soto source files from the AWS model files. Currently with each new release of Soto, the latest model files are copied from the <a href="https://github.com/aws/aws-sdk-go-v2">aws-sdk-go-v2</a> repository and new Soto source code is generated. This creates a lot of code, 1430181 lines at the last count. Along with the model files Soto is a very large repository to download.</p><p>Given Soto source code is generated, could we use a SwiftPM build plugin as a means to avoid downloading all this extra source code? The answer to that is yes, with some gotchas. There is a <a href="https://github.com/soto-project/soto-codegenerator/pull/58">pull request</a> (at the time of writing this it is still unmerged) that adds a build plugin to the SotoCodeGenerator project. The build plugin generates the Soto source code locally from a Smithy model file.</p><h2 id="using_plugin">Using plugin</h2><p>It is possible to use this build plugin, alongside <a href="https://github.com/soto-project/soto-core">SotoCore</a> (Repository containing the underlying code that runs Soto) to give a project access to an AWS service without including the whole of Soto as a dependency. You can set this up as follows.</p><p>SwiftPM build plugins are a Swift 5.6 feature so your <code>Package.swift</code> should indicate it needs Swift 5.6 or later</p><pre><code><span class="swift-comment">// swift-tools-version: 5.6</span></code></pre><p>Where previously you would include Soto as a dependency instead include the following</p><pre><code>.<span class="swift-call">package</span>(url: <span class="swift-string">"https://github.com/soto-project/soto-codegenerator"</span>, from: <span class="swift-string">"0.6.0"</span>),
.<span class="swift-call">package</span>(url: <span class="swift-string">"https://github.com/soto-project/soto-core.git"</span>, from: <span class="swift-string">"6.4.0"</span>)</code></pre><p>And the target you want to add the generated Soto code to should be setup as follows</p><pre><code>.<span class="swift-call">target</span>(
    name: <span class="swift-string">"MySotoServices"</span>,
    dependencies: [.<span class="swift-call">product</span>(name: <span class="swift-string">"SotoCore"</span>, package: <span class="swift-string">"soto-core"</span>)],
    plugins: [.<span class="swift-call">plugin</span>(name: <span class="swift-string">"SotoCodeGeneratorPlugin"</span>, package: <span class="swift-string">"soto-codegenerator"</span>)]
)</code></pre><p>You then need a couple of files from the Soto repository.</p><ul><li>The region endpoint definition file <a href="https://github.com/soto-project/soto/blob/main/models/endpoints/endpoints.json">endpoints.json</a></li><li>The model file for the service you want to use. You can find these <a href="https://github.com/soto-project/soto/blob/main/models/">here</a>.</li></ul><p>Copy both of these into the Source folder of the target where you want to generate the Soto Swift code. If you have multiple targets you are generating code in, you can copy endpoints.json to the root of your project instead. This will avoid having multiple copies of the file across multiple targets. Unless you are using a new region endpoint or new functionality from a service you shouldn't need to update these files again.</p><p>Finally if your target only includes AWS Smithy model files in it, you need to add a dummy empty Swift file to the folder. Otherwise SwiftPM will warn you have no source files for your target and not build the target. You could add a comment to this file to document where the generated Swift source files are.</p><p>Now build your target</p><pre><code>swift build
</code></pre><p>The build plugin will put the generated Swift code in <code>.build/plugins/outputs/&lt;package name&gt;/&lt;target name&gt;/SotoCodeGeneratorPlugin/GeneratedSources</code> and will include it in the list of Swift files for that target.</p><p>A sample project using the SotoCodeGenerator build plugin can be found <a href="https://github.com/adam-fowler/soto-codegenerator-plugin-test">here</a>.</p><h2 id="gotchas">Gotchas</h2><p>Earlier I mentioned there were some gotchas using the build plugin.</p><ul><li>If you are dependent on extension code in the Soto repository eg S3 multipart upload, STS/Cognito credential providers or DynamoDB Codable support they will not be available. You need to include Soto as a dependency to have access to these.</li><li>VS Code has some issues when working with build plugins. It looks like SourceKit-LSP is interfering with the build process and it fails to link symbols on the first attempt to build a project. Subsequent builds generally work, but not always. Also once you have generated your source code you need to restart the SourceKit-LSP server (either by restarting VS Code, or invoking the Developer: reload window command) to get code completion, go to definition etc to work. Hopefully these issues can be resolved in the near future.<ul></ul></li></ul><h2 id="removing_source_code_from_soto">Removing source code from Soto</h2><p>In theory I could replace all the generated source code in Soto with the build plugin. This isn't something I am ready to do yet. This feature is still experimental. Also build plugins require Swift 5.6 and Soto supports earlier versions of Swift so this is not possible until we drop support for those earlier versions.</p><p>Maybe at some point in the future though you might see a version of Soto with almost all of the Swift source code removed from it.</p>]]></content:encoded></item><item><guid>https://soto.codes/2022/06/v6-release.html</guid><link>https://soto.codes/2022/06/v6-release.html</link><title>Soto v6.0.0</title><description>Soto version 6.0.0 has been released. While this release includes a number of major changes many of these are internal and should not require much change from users of Soto. Upgrading to v6 should not be too painful.The big change that v6 brings in is how we generate the AWS service API files. A couple of years back AWS introduced &lt;a href="https://awslabs.github.io/smithy"&gt;Smithy&lt;/a&gt;: a new language for defining services and SDKs. They are now providing models for all of their services using this new…</description><pubDate>Tue, 21 Jun 2022 14:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="soto_v6_0_0">Soto v6.0.0</h1><p>Soto version 6.0.0 has been released. While this release includes a number of major changes many of these are internal and should not require much change from users of Soto. Upgrading to v6 should not be too painful.</p><h2 id="code_generation">Code Generation</h2><h3 id="smithy">Smithy</h3><p>The big change that v6 brings in is how we generate the AWS service API files. A couple of years back AWS introduced <a href="https://awslabs.github.io/smithy">Smithy</a>: a new language for defining services and SDKs. They are now providing models for all of their services using this new language. All new AWS SDKs are using the Smithy models as the source for code generation. I imagine at some point AWS will stop publishing the old json model format. Smithy has a number of advantages, one of the main ones being it has a published <a href="https://awslabs.github.io/smithy/1.0/spec/index.html">specification</a>. This makes source code generation considerably easier. From v6 onwards the Soto AWS service API files are generated from the Smithy files.</p><p>Along with the change to the service model format, we have moved the code generator out of the Soto repository into it's own repo: <a href="https://github.com/soto-project/soto-codegenerator">soto-codegenerator</a>.</p><p>Given we using a completely new source for service definitions there are some changes which have filtered into the generated files. Three services are no longer generated: SimpleDB, ImportExport, MobileAnalytics. A number of the service names have changed, if the name included "Service" in it before this has been removed and in some places capitalisation of various characters has changed.</p><h3 id="cleanup">Cleanup</h3><p>With this being a major release we have used this chance to clean up some variable and enum naming during code generation. Enums are now camel case, previously they were all lowercase. Variables that start with an uppercase acronym now capitalise correctly. Previously it would lowercase the first letter of the acronym and the rest would be left uppercase. This led to many variables being prefixed with <code>aWS</code>. These now have the prefix <code>aws</code>.</p><h2 id="http_client">HTTP Client</h2><p>The <code>AWSHTTPClient</code> protocol is no longer public. The library now requires that you use <a href="https://github.com/swift-server/async-http-client"><code>AsyncHTTPClient</code></a> from swift server team. This change has been implemented to reduce the API surface of Soto and to allow us more flexibility in how we integrate the HTTP client with the rest of the project.</p><h2 id="swift_concurrency">Swift Concurrency</h2><p>Version 5 of Soto included async/await versions of many of the APIs. Version 6 extends this, with a look to the future as well. There are new async versions of the S3 multipart upload/download functions. The big change though is adding <code>Sendable</code> protocol conformance to all the relevant public objects. This means Soto should be ready for Swift 6 when <code>Sendable</code> conformance is to be required for all async code. In general this is an additive change and will not affect the end user but it does impact APIs where the user provides a closure eg <code>AWSPayload.stream</code>. In these cases the closure will now have to be <code>@Sendable</code>.</p><h2 id="changes">Changes</h2><p>Here is a full list of changes in Soto v6.</p><h3 id="major">Major</h3><ul><li>Generate service files from Smithy model files.</li><li>Move Code Generator into its own repo <a href="https://github.com/soto-project/soto-codegenerator">soto-codegenerator</a>.</li><li><code>AWSHTTPClient</code>, <code>AWSHTTPRequest</code>, <code>AWSHTTPResponse</code> are no longer public symbols. User required to use <code>AsyncHTTPClient</code> as an HTTP client.</li><li>Add Sendable Conformance to all relevant objects/protocols. This includes AWSClient, AWSService, CredentialProvider and AWSShape.</li><li>Add support for automatic HTTP checksum calculation (crc32, crc32c, sha1 and sha256) where checksum tests are supported (S3).</li><li>Added <code>AWSBase64Data</code> to store base64 encoded data. This is to replace all instances of Data in AWS service API input/output shapes.</li><li>Move <code>_payloadOptions</code> to <code>AWSShape</code> and rename to <code>_options</code>.</li><li><code>AWSResponse.headers</code> type is now <code>NIOHTTP1.HTTPHeaders</code> instead of <code>[String: Any]</code>.</li><li><code>AWSPayload.stream</code> has the <code>byteBufferAllocator</code> parameter removed as it is no longer used.</li><li>Added <code>final</code> to all Shapes that are classes.</li><li>S3: Select Object Content code now uses <code>crc32</code> from SotoCore, instead of importing zlib. Target CSotoZlib has been removed.</li></ul><h3 id="minor">Minor</h3><ul><li>Add <code>xmlNamespace</code> to <code>AWSServiceConfig</code>.</li><li>Add <code>AWSShape</code> option <code>.checksumRequired</code> which calculates a checksum of the payload and places it in the relevant header.</li><li>Add <code>AWSShape</code> option <code>.md5ChecksumHeader</code> which indicates the shape has a <code>MD5-Content</code> header which will be calculated if the service config has option <code>.calculateMD5</code> set to true.</li><li>Add <code>Location.hostname</code> which is used for placing content in the hostname.</li><li>Add <code>Location.headerPrefix</code> which is used for placing a dictionary into multiple headers with the keys prefixed by a string. This was part of the S3 middleware but has now been generalised.</li><li>Added async version of <code>AWSClient.shutdown</code>.</li><li>Where operation input struct has deprecated members add an additional <code>init</code> which doesn't include deprecated members and deprecate old <code>init</code>.</li><li>S3: MD5 checksums are no longer automatically calculated (unless required). You can re-enable the automatic calculation of MD5 checksums using the S3 service option <code>.calculateMD5</code>.</li><li>S3: Added async versions of Multipart Upload/download functions</li><li>S3: Send <code>Expect: 100-continue</code> header to cancel large uploads early if AWS know they are going to fail.</li></ul><h3 id="patch">Patch</h3><ul><li>Remove retry on <code>NIOConnectionError</code> as <code>AsyncHTTPClient</code> does this for us.</li><li>Only retry on <code>HTTPClient.remoteConnectionClosed</code> in debug builds as this could retry non-idempotent calls even when they have been successful.</li><li>Set <code>user-agent</code> header to "Soto/6.0".</li><li>Fix V4 Signing bug where sequential spaces have to be removed from header values when building canonical request.</li><li>S3: S3RequestMiddleware now preserves trailing "/" when reconstructing URL</li><li>S3: Percent encode additional characters in URL paths, to support S3 like services that require this.</li></ul>]]></content:encoded></item><item><guid>https://soto.codes/2021/10/async-await.html</guid><link>https://soto.codes/2021/10/async-await.html</link><title>Soto and Swift concurrency</title><description>The new release of Swift 5.5 comes with the much anticipated Swift concurrency model. The changes include the async/await syntax, structured concurrency, async sequences plus much more. This is an exciting time to be working in Swift. With the release of v5.9.0 of Soto we have added support for some of these new features.First, all the service commands which return an &lt;code&gt;EventLoopFuture&lt;/code&gt; of the response from AWS now have an async/await equivalent. If you are running in an async context then the…</description><pubDate>Tue, 26 Oct 2021 09:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="soto_and_swift_concurrency">Soto and Swift concurrency</h1><p>The new release of Swift 5.5 comes with the much anticipated Swift concurrency model. The changes include the async/await syntax, structured concurrency, async sequences plus much more. This is an exciting time to be working in Swift. With the release of v5.9.0 of Soto we have added support for some of these new features.</p><h2 id="service_api_files">Service API files</h2><p>First, all the service commands which return an <code>EventLoopFuture</code> of the response from AWS now have an async/await equivalent. If you are running in an async context then the following code from previous versions of Soto</p><pre><code><span class="swift-keyword">let</span> request = <span class="swift-type">S3</span>.<span class="swift-type">GetObjectRequest</span>(bucket: <span class="swift-string">"my-bucket"</span>, key: <span class="swift-string">"my-file"</span>)
<span class="swift-keyword">let</span> responseFuture = s3.<span class="swift-call">getObject</span>(request).<span class="swift-call">whenComplete</span> { result <span class="swift-keyword">in
    switch</span> result {
    <span class="swift-keyword">case</span> .<span class="swift-dotAccess">success</span>(<span class="swift-keyword">let</span> response):
        <span class="swift-call">processResponse</span>(response)
    <span class="swift-keyword">case</span> .<span class="swift-dotAccess">failure</span>(<span class="swift-keyword">let</span> error):
        <span class="swift-call">processError</span>(error)
    }
}</code></pre><p>Can now be replaced with</p><pre><code><span class="swift-keyword">do</span> {
    <span class="swift-keyword">let</span> request = <span class="swift-type">S3</span>.<span class="swift-type">GetObjectRequest</span>(bucket: <span class="swift-string">"my-bucket"</span>, key: <span class="swift-string">"my-file"</span>)
    <span class="swift-keyword">let</span> response = <span class="swift-keyword">try await</span> s3.<span class="swift-call">getObject</span>(request)
    <span class="swift-call">processResponse</span>(response)
} <span class="swift-keyword">catch</span> {
    <span class="swift-call">processError</span>(error)
}</code></pre><p>The new code is cleaner and easier to read. It looks more like your standard synchronous code and doesn't rely on closures for processing results of asynchronous functions.</p><h2 id="paginators">Paginators</h2><p>Swift 5.5 adds the protocol <code>AsyncSequence</code>. This is similar to the protocol <code>Sequence</code> in that you can create an iterator to iterate through all the elements of the <code>AsyncSequence</code>. The exception is to get next element of an <code>AsyncIterator</code> is an async operation. Soto uses these to represent paginators. Each call to <code>next()</code> will get the next page of results from AWS. For an operation that can be paginated you can create an <code>AsyncSequence</code> paginator and then access all the results in a similar way to how you would with a <code>Sequence</code>, as you see below.</p><pre><code><span class="swift-keyword">var</span> results: [<span class="swift-type">TestObject</span>] = []
<span class="swift-keyword">let</span> queryRequest = <span class="swift-type">DynamoDB</span>.<span class="swift-type">QueryInput</span>(
    expressionAttributeValues: [<span class="swift-string">":pk"</span>: .<span class="swift-call">s</span>(<span class="swift-string">"id"</span>), <span class="swift-string">":sk"</span>: .<span class="swift-call">n</span>(<span class="swift-string">"2"</span>)],
    keyConditionExpression: <span class="swift-string">"id = :id and version &gt;= :version"</span>,
    tableName: tableName
)
<span class="swift-keyword">let</span> paginator = <span class="swift-type">Self</span>.<span class="swift-property">dynamoDB</span>.<span class="swift-call">queryPaginator</span>(queryRequest, type: <span class="swift-type">TestObject</span>.<span class="swift-keyword">self</span>)
<span class="swift-comment">// treat paginator as sequence of results</span>
<span class="swift-keyword">for try await</span> response <span class="swift-keyword">in</span> paginator {
    results.<span class="swift-call">append</span>(contentsOf: response.<span class="swift-property">items</span> ?? [])
}</code></pre><h2 id="waiters">Waiters</h2><p>Waiters are a relatively new feature of Soto but they also get an async/await API. In a similar manner to the service API commands, we add an equivalent async/await function for every waiter function that returns an <code>EventLoopFuture</code>. Below the code from previous versions of Soto creates a DynamoDB table and then waits for it to be ready using the waiter <code>waitUntilTableExists</code>.</p><pre><code><span class="swift-keyword">let</span> request = <span class="swift-type">DynamoDB</span>.<span class="swift-type">CreateTableInput</span>(
    attributeDefinitions: [.<span class="swift-keyword">init</span>(attributeName: <span class="swift-string">"pk"</span>, attributeType: .<span class="swift-dotAccess">s</span>)],
    keySchema: [.<span class="swift-keyword">init</span>(attributeName: <span class="swift-string">"pk"</span>, keyType: .<span class="swift-dotAccess">hash</span>)],
    tableName: <span class="swift-string">"my-table"</span>
)
dynamoDB.<span class="swift-call">createTable</span>(request)
    .<span class="swift-call">flatMap</span> { <span class="swift-keyword">_ in
        return</span> dynamoDB.<span class="swift-call">waitUntilTableExists</span>(.<span class="swift-keyword">init</span>(tableName: <span class="swift-string">"my-table"</span>))
    }
    .<span class="swift-call">whenComplete</span> { result <span class="swift-keyword">in</span>
        ...
    }</code></pre><p>can be replaced with</p><pre><code><span class="swift-keyword">let</span> request = <span class="swift-type">DynamoDB</span>.<span class="swift-type">CreateTableInput</span>(
    attributeDefinitions: [.<span class="swift-keyword">init</span>(attributeName: <span class="swift-string">"pk"</span>, attributeType: .<span class="swift-dotAccess">s</span>)],
    keySchema: [.<span class="swift-keyword">init</span>(attributeName: <span class="swift-string">"pk"</span>, keyType: .<span class="swift-dotAccess">hash</span>)],
    tableName: <span class="swift-string">"my-table"</span>
)
<span class="swift-keyword">_</span> = <span class="swift-keyword">try await</span> dynamoDB.<span class="swift-call">createTable</span>(request)
<span class="swift-keyword">try await</span> dynamoDB.<span class="swift-call">waitUntilTableExists</span>(.<span class="swift-keyword">init</span>(tableName: <span class="swift-string">"my-table"</span>))</code></pre><p>In the original code you can see that two commands have been chained together using <code>flatMap</code>. Chaining of <code>EventLoopFutures</code> has been one of the harder things to get right when working with Swift NIO. When there were issues with your code, the compiler did not always produce very helpful error messages. The new async/await code removes the chaining and thus is easier to work with.</p><h2 id="future">Future</h2><p>Currently the Soto support for the new Swift concurrency is a thin layer that fits on top of the existing APIs. The internals of Soto are still the same Swift NIO code that was there before. This is to ensure the existing <code>EventLoopFuture</code> APIs are still available for users who cannot upgrade to Swift 5.5, or who would still prefer to work with these APIs.</p><p>At some point though there will be a version of Soto that replaces the Swift NIO internals with a Swift concurrency implementation. This will be a breaking change and from that point the <code>EventLoopFuture</code> APIs will no longer be available.</p>]]></content:encoded></item><item><guid>https://soto.codes/2021/07/waiters.html</guid><link>https://soto.codes/2021/07/waiters.html</link><title>Waiting</title><description>With the release of Soto 5.7 we introduce a new feature: waiters. A waiter is a client side abstraction that polls an AWS resource until a desired state is reached. This is a common task with services that create resources asynchronously. Writing the code to continually poll a resource for a state can be error prone. Writing loops in asynchronous code can be particularly difficult. Waiters are provided to take this responsibility away from the client. Below is an example of creating a DynamoDB table,…</description><pubDate>Thu, 22 Jul 2021 11:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="waiting">Waiting</h1><p>With the release of Soto 5.7 we introduce a new feature: waiters. A waiter is a client side abstraction that polls an AWS resource until a desired state is reached. This is a common task with services that create resources asynchronously. Writing the code to continually poll a resource for a state can be error prone. Writing loops in asynchronous code can be particularly difficult. Waiters are provided to take this responsibility away from the client. Below is an example of creating a DynamoDB table, waiting for it to become active and then putting an item in it.</p><pre><code><span class="swift-keyword">let</span> input = <span class="swift-type">DynamoDB</span>.<span class="swift-type">CreateTableInput</span>(
    attributeDefinitions: [.<span class="swift-keyword">init</span>(attributeName: <span class="swift-string">"pk"</span>, attributeType: .<span class="swift-dotAccess">s</span>)],
    keySchema: [.<span class="swift-keyword">init</span>(attributeName: <span class="swift-string">"pk"</span>, keyType: .<span class="swift-dotAccess">hash</span>)],
    provisionedThroughput: .<span class="swift-keyword">init</span>(readCapacityUnits: <span class="swift-number">1</span>, writeCapacityUnits: <span class="swift-number">1</span>),
    tableName: <span class="swift-string">"test-table"</span>
)
<span class="swift-keyword">let</span> futureResult = dynamoDB.<span class="swift-call">createTable</span>(input)
    .<span class="swift-call">flatMap</span> { <span class="swift-keyword">_</span> -&gt; <span class="swift-type">EventLoopFuture</span>&lt;<span class="swift-type">Void</span>&gt; <span class="swift-keyword">in</span>
        dynamoDB.<span class="swift-call">waitUntilTableExists</span>(.<span class="swift-keyword">init</span>(tableName: <span class="swift-string">"test-table"</span>))
    }
    .<span class="swift-call">flatMap</span> { <span class="swift-keyword">_</span> -&gt; <span class="swift-type">EventLoopFuture</span>&lt;<span class="swift-type">DynamoDB</span>.<span class="swift-type">PutItemOutput</span>&gt; <span class="swift-keyword">in</span>
        dynamoDB.<span class="swift-call">putItem</span>(.<span class="swift-keyword">init</span>(item: [<span class="swift-string">"pk"</span>: .<span class="swift-call">s</span>(<span class="swift-string">"test"</span>)], tableName: <span class="swift-string">"test-table"</span>))
    }</code></pre><p>Most of the code in this sample is setting up the DynamoDB table. The code to wait for for the table to be active has been reduced to the single line <code>dynamoDB.waitUntilTableExists(...)</code>.</p><p>AWS provide models for waiters for many situations where you might be waiting on a resource state. Examples include waiting for an EC2 instance to be running <code>EC2.waitUntilInstanceRunning</code>, a RDS database to be available <code>RDS.waitUntilDBInstanceAvailable</code>, an IAM Role to exist <code>IAM.waitUntilRoleExists</code> or for a S3 Object to exist <code>S3.waitUntilObjectExists</code>.</p>]]></content:encoded></item><item><guid>https://soto.codes/2021/03/soto-cognito-authentication-kit.html</guid><link>https://soto.codes/2021/03/soto-cognito-authentication-kit.html</link><title>Soto Cognito Authentication Kit</title><description>We'd like to announce a new Soto Project package. Soto Cognito Authentication Kit provides an easy to use interface to AWS Cognito. Through Soto Cognito Authentication Kit you can create users, authenticate via username and password, verify access and id JWT tokens, refresh these tokens and authenticate using Secure Remote Password. Along with Cognito Identity it can provide AWS credentials for authenticated users, thus allowing them access to AWS resources. The library has supports for running with either…</description><pubDate>Wed, 3 Mar 2021 17:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="soto_cognito_authentication_kit">Soto Cognito Authentication Kit</h1><p>We'd like to announce a new Soto Project package. Soto Cognito Authentication Kit provides an easy to use interface to AWS Cognito. Through Soto Cognito Authentication Kit you can create users, authenticate via username and password, verify access and id JWT tokens, refresh these tokens and authenticate using Secure Remote Password. Along with Cognito Identity it can provide AWS credentials for authenticated users, thus allowing them access to AWS resources. The library has supports for running with either a client authenticated with AWS credentials or an unautheticated client.</p><p>Soto Cognito Authentication Kit has been around for a year or so already, but it is now an official Soto Project package. You can find it <a href="https://github.com/soto-project/soto-cognito-authentication-kit">here</a>.</p>]]></content:encoded></item><item><guid>https://soto.codes/2021/02/signing-urls-and-headers.html</guid><link>https://soto.codes/2021/02/signing-urls-and-headers.html</link><title>Signing URLs and headers</title><description>I have previously written an article on generating &lt;a href="/2020/12/presigned-urls.html"&gt;pre-signed URLs for S3&lt;/a&gt;. This article though covers the situation where a signed URL or set of signed headers are required for IAM authentication outside of the AWS service APIs. Below is detailed two different methods for doing this.The first method uses the service object from a Soto service library. This is the easier of the two methods but requires an &lt;code&gt;AWSClient&lt;/code&gt; to manage your AWS credentials and…</description><pubDate>Wed, 3 Feb 2021 15:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="signing_urls_and_headers">Signing URLs and headers</h1><p>I have previously written an article on generating <a href="/2020/12/presigned-urls.html">pre-signed URLs for S3</a>. This article though covers the situation where a signed URL or set of signed headers are required for IAM authentication outside of the AWS service APIs. Below is detailed two different methods for doing this.</p><h2 id="1__using_a_service_object">1) Using a service object</h2><p>The first method uses the service object from a Soto service library. This is the easier of the two methods but requires an <code>AWSClient</code> to manage your AWS credentials and that you have a service object with correct signing name. The method uses either <code>AWSService.signURL</code> for signing URLS or <code>AWSService.signHeaders</code> for generating signed headers.</p><p>In the example below we have a function for signing requests to a AWS managed Elasticsearch instance. The function uses <code>signHeaders</code> as the signed URL query parameters would confuse the Elasticsearch instance.</p><pre><code><span class="swift-keyword">func</span> elasticSearchExecute(
    url: <span class="swift-type">URL</span>, 
    method: <span class="swift-type">HTTPMethod</span>, 
    headers: <span class="swift-type">HTTPHeaders</span>, 
    body: <span class="swift-type">ByteBuffer</span>? = <span class="swift-keyword">nil</span>
) -&gt; <span class="swift-type">EventLoopFuture</span>&lt;<span class="swift-type">HTTPClient</span>.<span class="swift-type">Response</span>&gt; {
    <span class="swift-keyword">let</span> es = <span class="swift-type">ElasticsearchService</span>(client: awsClient, region: .<span class="swift-dotAccess">useast1</span>)
    <span class="swift-keyword">return</span> es.<span class="swift-call">signHeaders</span>(
        url: url,
        httpMethod: method,
        headers: headers,
        body: body.<span class="swift-call">map</span> { .<span class="swift-call">byteBuffer</span>($0) } ?? .<span class="swift-dotAccess">empty</span>
    ).<span class="swift-call">flatMap</span> { signedHeaders <span class="swift-keyword">in
        let</span> request = <span class="swift-keyword">try</span>! <span class="swift-type">HTTPClient</span>.<span class="swift-type">Request</span>(
            url: url,
            method: method,
            headers: signedHeaders,
            body: body.<span class="swift-call">map</span> { .<span class="swift-call">byteBuffer</span>($0) }
        )
        <span class="swift-keyword">return</span> httpClient.<span class="swift-call">execute</span>(request: request, logger: logger)
    }
}</code></pre><h2 id="2__using_the_soto_signer_directly">2) Using the Soto signer directly</h2><p>The second method uses <code>SotoSignerV4</code> directly. This requires you have your AWS credentials to hand to initialize the <code>AWSSignerV4</code>. We call <code>AWSSignerV4.processURL</code> on the URL before signing it to clean it up. Cleaning up the URL means sorting the query parameters in alphabetical order and percent encoding as AWS requires.</p><p>In the example below we are signing a request to an API Gateway REST interface. Please note for API Gateway interfaces the signing name is <code>execute-api</code>.</p><pre><code><span class="swift-keyword">import</span> SotoSignerV4

<span class="swift-keyword">func</span> apiGatewayExecute(
    url: <span class="swift-type">URL</span>, 
    method: <span class="swift-type">HTTPMethod</span>, 
    headers: <span class="swift-type">HTTPHeaders</span>, 
    body: <span class="swift-type">ByteBuffer</span>? = <span class="swift-keyword">nil</span>
) -&gt; <span class="swift-type">EventLoopFuture</span>&lt;<span class="swift-type">HTTPClient</span>.<span class="swift-type">Response</span>&gt; {
    <span class="swift-keyword">let</span> credentials: <span class="swift-type">Credential</span> = <span class="swift-type">StaticCredential</span>(
        accessKeyId: <span class="swift-string">"_MYACCESSKEY_"</span>, 
        secretAccessKey: <span class="swift-string">"_MYSECRETACCESSKEY_"</span>
    )
    <span class="swift-keyword">let</span> signer = <span class="swift-type">AWSSigner</span>(credentials: credentials, name: <span class="swift-string">"execute-api"</span>, region: <span class="swift-string">"us-east-1"</span>)
    <span class="swift-comment">// clean up URL</span>
    <span class="swift-keyword">let</span> processedURL = signer.<span class="swift-call">processURL</span>(url: url)!
    <span class="swift-keyword">let</span> signedHeaders = signer.<span class="swift-call">signHeaders</span>(
        url: processedURL,
        method: method,
        headers: headers,
        body: body.<span class="swift-call">map</span> { .<span class="swift-call">byteBuffer</span>($0) }
    )
    <span class="swift-keyword">let</span> request = <span class="swift-keyword">try</span>! <span class="swift-type">HTTPClient</span>.<span class="swift-type">Request</span>(
        url: processedURL,
        method: method,
        headers: signedHeaders,
        body: body.<span class="swift-call">map</span> { .<span class="swift-call">byteBuffer</span>($0) }
    )
    <span class="swift-keyword">return</span> httpClient.<span class="swift-call">execute</span>(request: request, logger: logger)
}</code></pre><p>Both of these examples use the swift-server <a href="https://github.com/swift-server/async-http-client">AsyncHTTPClient</a> but you should be able to use any HTTP client using these methods.</p>]]></content:encoded></item><item><guid>https://soto.codes/2021/01/soto-s3-file-transfer.html</guid><link>https://soto.codes/2021/01/soto-s3-file-transfer.html</link><title>Soto S3 File Transfer</title><description>We'd like to announce a new package available from the Soto project. Soto S3 File Transfer has been implemented to ease moving of files between your local file system and S3.It provides APIs for copying individual files from your local filesystem to S3, S3 back to your file system and from one S3 bucket to another. If files are above a certain size then the transfer manager will use S3 multi-part upload or copy.The upload to S3, download from S3 and copy paths are also provided for folders. When copying a…</description><pubDate>Tue, 12 Jan 2021 11:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="soto_s3_file_transfer">Soto S3 File Transfer</h1><p>We'd like to announce a new package available from the Soto project. Soto S3 File Transfer has been implemented to ease moving of files between your local file system and S3.</p><p>It provides APIs for copying individual files from your local filesystem to S3, S3 back to your file system and from one S3 bucket to another. If files are above a certain size then the transfer manager will use S3 multi-part upload or copy.</p><p>The upload to S3, download from S3 and copy paths are also provided for folders. When copying a folder multiple files will be uploaded in parallel. In addition to a simple copy folder operation there are also sync folder operations which will only copy files that are newer in the source folder and if desired delete files that exist in the destination but not the source folder.</p><p>Soto S3 File Transfer can be found <a href="https://github.com/soto-project/soto-s3-file-transfer">here</a>.</p>]]></content:encoded></item><item><guid>https://soto.codes/2020/12/presigned-urls.html</guid><link>https://soto.codes/2020/12/presigned-urls.html</link><title>Pre-signed URLs for S3</title><description>One of the most common questions we get about Soto is "How do I pre-sign a URL for uploading to S3?". This is a common pattern where a server provides a pre-signed URL to a client. A pre-signed URL allows you to grant temporary access to a single file in an S3 bucket to someone who normally does not have access. The URL is signed with your credentials and it gives anyone the ability to upload to that object in S3 while it is still valid. Be careful, to not provide these too freely.Assuming you already have…</description><pubDate>Wed, 16 Dec 2020 17:00:00 +0000</pubDate><content:encoded><![CDATA[<h1 id="pre_signed_urls_for_s3">Pre-signed URLs for S3</h1><p>One of the most common questions we get about Soto is "How do I pre-sign a URL for uploading to S3?". This is a common pattern where a server provides a pre-signed URL to a client. A pre-signed URL allows you to grant temporary access to a single file in an S3 bucket to someone who normally does not have access. The URL is signed with your credentials and it gives anyone the ability to upload to that object in S3 while it is still valid. Be careful, to not provide these too freely.</p><h2 id="uploading_to_s3">Uploading to S3</h2><p>Assuming you already have an <code>AWSClient</code>, the following will generate an <code>EventLoopFuture</code> that will be fulfilled with a pre-signed URL for uploading to S3 .</p><pre><code><span class="swift-keyword">let</span> s3 = <span class="swift-type">S3</span>(client: awsClient, region: .<span class="swift-dotAccess">useast1</span>)
<span class="swift-keyword">let</span> signedURLFuture = <span class="swift-keyword">try</span> s3.<span class="swift-call">signURL</span>(
    url: <span class="swift-type">URL</span>(string: <span class="swift-string">"https://&lt;my-bucket&gt;.s3.us-east-1.amazonaws.com/&lt;my-object&gt;"</span>)!,
    httpMethod: .<span class="swift-dotAccess">PUT</span>,
    expires: .<span class="swift-call">minutes</span>(<span class="swift-number">15</span>)
)</code></pre><p>Replace <code>&lt;my-bucket&gt;</code> with the name of your S3 bucket and <code>&lt;my-object&gt;</code> with the name of the object you want to upload. In this example I am assuming your bucket is in the <code>us-east-1</code> region. You should replace this, both in the <code>S3</code> initialization and the unsigned URL, with the region your bucket exists in.</p><p>The function <code>signURL</code> returns an <code>EventLoopFuture&lt;URL&gt;</code> and not a <code>URL</code> because the <code>AWSClient</code> which manages credential acquisition, required to sign your URL, could still be in the process of acquiring those credentials.</p><h2 id="downloading_from_s3">Downloading from S3</h2><p>To generate a URL that downloads a file from S3 all you need to do is replace the <code>.PUT</code> with a <code>.GET</code>.</p><pre><code><span class="swift-keyword">let</span> s3 = <span class="swift-type">S3</span>(client: awsClient, region: .<span class="swift-dotAccess">useast1</span>)
<span class="swift-keyword">let</span> signedURLFuture = <span class="swift-keyword">try</span> s3.<span class="swift-call">signURL</span>(
    url: <span class="swift-type">URL</span>(string: <span class="swift-string">"https://&lt;my-bucket&gt;.s3.us-east-1.amazonaws.com/&lt;my-object&gt;"</span>)!,
    httpMethod: .<span class="swift-dotAccess">GET</span>,
    expires: .<span class="swift-call">minutes</span>(<span class="swift-number">15</span>)
)</code></pre><h2 id="including_header_values">Including header values</h2><p>If you want to include some headers values with the URL you have to include the headers while signing it and the client will be required to include exactly the same headers when they use the URL. The following will provide a URL that uploads an object with content type set to "application/json" and canned ACL set to "public-read".</p><pre><code><span class="swift-keyword">let</span> signedURLFuture = <span class="swift-keyword">try</span> s3.<span class="swift-call">signURL</span>(
    url: <span class="swift-type">URL</span>(string: <span class="swift-string">"https://&lt;my-bucket&gt;.s3.us-east-1.amazonaws.com/&lt;my-object&gt;"</span>)!,
    httpMethod: .<span class="swift-dotAccess">PUT</span>,
    headers: [<span class="swift-string">"Content-Type"</span>: <span class="swift-string">"application/json"</span>, <span class="swift-string">"x-amz-acl"</span>: <span class="swift-string">"public-read"</span>],
    expires: .<span class="swift-call">minutes</span>(<span class="swift-number">15</span>)
)</code></pre><p>You can find a list of possible headers <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html">here</a>.</p>]]></content:encoded></item></channel></rss>