AWS SDK for Swift

repository·main·Indexed 19 days ago

https://github.com/awslabs/aws-sdk-swift

A library for Swift developers to interact with AWS services. It includes service-specific APIs and core runtime modules such as AWSClientRuntime, AWSSDKChecksums, AWSSDKCommon, AWSSDKEventStreamsAuth, AWSSDKHTTPAuth, and AWSSDKIdentity. The repository also provides the AWSSDKSwiftCLI for automating development tasks like generating package manifests and documentation indices, as well as integration testing tools for EC2 and ECS environments.

Tokens
7.9K
Snippets
21
Records
41
Agent score
64%

What's inside aws-sdk-swift

  1. Smithy Runtime Modules

    main

    The SDK utilizes several Smithy runtime modules that handle core protocol and communication logic. These modules include support for various serialization formats (JSON, XML, CBOR), HTTP communication, authentication, retries, and event streams.

    Key modules include:

    • ClientRuntime: Core client execution logic.
    • SmithyHTTPClient: HTTP client abstractions.
    • SmithySerialization: Handling of data formats like SmithyJSON, SmithyXML, and SmithyCBOR.
    • SmithyRetries: Logic for handling request retries.
    • SmithyEventStreams: Support for streaming data and event stream authentication.
    • SmithyChecksums: Data integrity via checksums.
  2. Identify and avoid System Programming Interface (SPI) APIs

    main

    The AWS SDK for Swift uses the Swift "System Programming Interface" (SPI) feature to distinguish between public APIs intended for customers and internal APIs.

    How to identify SPI APIs: Look for interfaces marked with the @_spi annotation. These are not intended for customer use and may be altered without notice.

    If your development requires access to an interface marked with @_spi, do not use it directly; instead, start a discussion with the SDK developers to find a supported solution.

  3. Understand the AWS SDK for Swift versioning format

    main

    The AWS SDK for Swift follows Semantic Versioning using the format <major>.<minor>.<patch>.

    • major: Indicates significant, breaking API changes. Upgrading to a new major version will require additional development work.
    • minor: Indicates changes that are not breaking but may require developer attention (e.g., behavior changes, feature deprecations, or dropping support for specific Xcode/Swift/platform versions).
    • patch: Indicates less significant changes that should not require additional development or change SDK behavior. Patch releases typically include updates to AWS service APIs and are released frequently (often every business day).
    <major>.<minor>.<patch>
  4. Understand the AWS SDK for Swift runtime modules

    main

    The SDK is composed of several core runtime modules located under Sources/Core/ that provide essential functionalities. Understanding these helps in navigating the SDK's underlying architecture:

    • AWSClientRuntime: Provides most AWS-specific runtime functionalities, including concrete types, protocols, and enums. It serves as a central module with several other runtime dependencies.
    • AWSSDKChecksums: Handles checksum implementations for AWS requests.
    • AWSSDKCommon: Contains concrete types used across other runtime modules.
    • AWSSDKEventStreamsAuth: Provides concrete types for signing AWS event stream messages.
    • AWSSDKHTTPAuth: Contains the AWS SigV4 signer and types related to the authentication flow.
    • AWSSDKIdentity: Manages AWS credentials and identity resolvers.

    For deeper technical details, refer to the AWS Runtime Module Documentation in the API reference.

  5. AWS Runtime Modules

    main

    The AWS-specific runtime modules build upon the Smithy foundation to provide AWS-specific functionality, such as identity management and specialized authentication protocols.

    Key modules include:

    • AWSClientRuntime: AWS-specific client runtime logic.
    • AWSSDKCommon: Common utilities used across AWS services.
    • AWSSDKIdentity: Identity management for AWS requests.
    • AWSSDKHTTPAuth: AWS-specific HTTP authentication mechanisms.
  6. Understand AWS SDK for Swift release qualifiers

    main

    The AWS SDK for Swift uses specific suffixes in its published artifact versions to communicate stability and suitability for production. Use these qualifiers to determine if a version is safe for your workload:

    • -alpha:

      • Not for production.
      • Released for feedback purposes only.
      • Not feature complete.
      • May contain bugs or performance issues.
      • APIs and types are subject to change, which may cause migration issues.
    • -beta:

      • Not for production.
      • Feature complete.
      • May still contain bugs or performance issues.
      • APIs and types are mostly stabilized, but future releases may still cause migration issues.
      • Corresponds to the "Developer Preview" phase of the AWS SDK maintenance policy.
  7. How AWS Service Client Libraries are updated

    main

    The AWS SDK for Swift includes individual libraries for every AWS service (such as S3, EC2, etc.), containing the service client, model types, and support code.

    When you update the SDK version, it updates all service libraries currently in use as well as all supporting runtime components. Note that while services are currently bundled, they may be published separately in the future.

  8. Use the deploy-docker-to-ecr.sh script

    main

    The ./deploy-docker-to-ecr.sh script builds a Docker image containing the test application (ECSIntegTestApp) and pushes it to a private ECR repository.

    Arguments:

    1. account_id (Required): The AWS Account ID used to construct the ECR repository URL.
    2. region (Optional): The AWS region to use.
    3. ecr_repo_name (Optional): The name of the ECR repository to use.

    Usage Examples:

    • Basic: ./deploy-docker-to-ecr.sh 123456789012
    • With region: ./deploy-docker-to-ecr.sh 123456789012 us-west-2
    • With region and repo name: ./deploy-docker-to-ecr.sh 123456789012 us-west-2 my-repo-name

    Note: When prompted, use your AWS credentials to sign your Docker daemon to the AWS ECR repository to allow the image push.

    ./deploy-docker-to-ecr.sh 123456789012 us-west-2 my-repo-name
  9. Prepare ECS integration testing environment

    main

    Before running ECS integration tests for aws-sdk-swift, you must deploy the necessary Docker images to Amazon ECR. This package is designed to run inside an ECS cluster. The deployment script ./deploy-docker-to-ecr.sh only needs to be executed once per AWS account, unless you update underlying package versions or the test runner inside the ECS container.

    # Ensure the script is executable
    chmod +x deploy-docker-to-ecr.sh
    
    # Execute the deployment script with your AWS Account ID
    ./deploy-docker-to-ecr.sh 123456789012
  10. Enable MD5 checksum compatibility for S3-like third-party services

    main

    The AWS SDK for Swift has moved away from MD5 for payload checksums in favor of more secure algorithms. This change can cause issues with certain third-party "S3-like" storage services that expect MD5 for the S3 DeleteObjects operation.

    To resolve this, you can implement and register a custom HttpInterceptorProvider that forces the SDK to use the Content-MD5 header for DeleteObjects requests.

    Warning: This approach requires reading the entire request body into memory to compute the MD5 hash, which may cause performance issues or high memory usage for extremely large request bodies. Do not use this interceptor with AWS services or third-party services that already support the SDK's modern checksum options.

    class DeleteObjectsMD5InterceptorProvider: HttpInterceptorProvider {
    
        class DeleteObjectsMD5Interceptor<InputType, OutputType>: Interceptor {
            typealias RequestType = HTTPRequest
            typealias ResponseType = HTTPResponse
    
            let MD5_HEADER = "Content-MD5"
            let OTHER_CHECKSUMS_PREFIX = "x-amz-checksum-"
            let OTHER_CHECKSUMS_SDK_PREFIX = "x-amz-sdk-checksum-"
    
            func readAfterSerialization(context: some AfterSerialization<InputType, HTTPRequest>) async throws {
                let request = context.getRequest()
    
                let bodyData: Data?
                switch request.body {
                case .stream(let stream):
                    bodyData = try await stream.readToEndAsync()
                case .data:
                    return
                case .noStream:
                    bodyData = nil
                }
    
                request.body = .data(bodyData)
            }
    
            func modifyBeforeSigning(context: some MutableRequest<InputType, HTTPRequest>) async throws {
                let attributes = context.getAttributes()
                let request = context.getRequest()
                let body = request.body
    
                guard attributes.getServiceName() == "S3", attributes.getOperation() == "deleteObjects" else { return }
    
                let checksumHeaders = request.headers.headers.map { $0.name }.filter { $0.hasPrefix(OTHER_CHECKSUMS_PREFIX) }
                checksumHeaders.forEach { request.headers.remove(name: $0) }
                let checksumSDKHeaders = request.headers.headers.map { $0.name }.filter { $0.hasPrefix(OTHER_CHECKSUMS_SDK_PREFIX) }
                checksumSDKHeaders.forEach { request.headers.remove(name: $0) }
                let checksumTrailingHeaders = request.trailingHeaders.headers.map { $0.name }.filter { $0.hasPrefix(OTHER_CHECKSUMS_PREFIX) }
                checksumTrailingHeaders.forEach { request.trailingHeaders.remove(name: $0) }
    
                if case .data(let data) = body, let data {
                    let md5data = try data.computeMD5()
                    request.headers.add(name: MD5_HEADER, value: md5data.base64EncodedString())
                }
            }
        }
    
        func create<InputType, OutputType>() -> any Interceptor<InputType, OutputType, HTTPRequest, HTTPResponse> {
            return DeleteObjectsMD5Interceptor()
        }
    }
    
    // Configuration
    let config = try await S3Client.Config(
        region: "us-east-1",
        httpInterceptorProviders: [DeleteObjectsMD5InterceptorProvider()]
    )
    let client = S3Client(config: config)
  11. Configure local development via local.properties

    main

    Developers of the SDK can modify build behavior by defining a local.properties file at the root of the project. This file allows for customizing service generation and including external builds (like smithy-swift) for local development.

    Important Note: These instructions are intended for contributors to the SDK itself. End-users looking to use the SDK to access AWS services should refer to the main README.

    # comma separated list of paths to `includeBuild()`
    # This is useful for local development of smithy-swift in particular 
    compositeProjects=../smithy-swift
    
    # comma separated list of services to exclude from generation from sdk-codegen.
    # specify service.VERSION matching the filenames in the models directory `aws-models -> service.VERSION.json`
    excludeModels=rds-data.2018-08-01, groundstation.2019-05-23 
    
    # comma separated list of services to generate from sdk-codegen.
    # specify service.VERSION matching the filenames in the models directory `aws-models -> service.VERSION.json`.
    onlyIncludeModels=lambda.2015-03-31
    
    # when generating aws services build as a standalong project or not (rootProject = true)
    buildStandaloneSdk=true