$npx -y skills add aws/agent-toolkit-for-aws --skill aws-sdk-swift-usageAWS SDK for Swift development patterns. Use when writing Swift code that uses AWS services via aws-sdk-swift package.
| 1 | # AWS SDK for Swift |
| 2 | |
| 3 | ## Async Code Structure |
| 4 | |
| 5 | All SDK operations are async. Use `@main` entry point: |
| 6 | |
| 7 | ```swift |
| 8 | @main |
| 9 | struct Main { |
| 10 | static func main() async throws { |
| 11 | let client = try await S3Client() |
| 12 | // ... async operations |
| 13 | } |
| 14 | } |
| 15 | ``` |
| 16 | |
| 17 | ## CRITICAL: Use Struct Config Types |
| 18 | |
| 19 | NEVER use `S3ClientConfiguration` or `DynamoDBClientConfiguration` - these are DEPRECATED classes. |
| 20 | |
| 21 | ALWAYS use the struct-based config types: |
| 22 | |
| 23 | - `S3Client.S3ClientConfig` (not S3ClientConfiguration) |
| 24 | - `DynamoDBClient.DynamoDBClientConfig` (not DynamoDBClientConfiguration) |
| 25 | - `STSClient.STSClientConfig` (not STSClientConfiguration) |
| 26 | |
| 27 | Config parameters MUST be in declaration order. Region is ALWAYS required when creating a config. Check the service client source for exact order. |
| 28 | |
| 29 | ```swift |
| 30 | // CORRECT - struct config |
| 31 | let config = try await S3Client.S3ClientConfig(region: "us-west-2") |
| 32 | let client = S3Client(config: config) |
| 33 | |
| 34 | // WRONG - deprecated class |
| 35 | // let config = try await S3Client.S3ClientConfiguration(region: "us-west-2") |
| 36 | ``` |
| 37 | |
| 38 | ## Client Creation |
| 39 | |
| 40 | All service clients follow the same pattern: `<Service>Client` with `<Service>Client.<Service>ClientConfig`. |
| 41 | |
| 42 | Model types (structs/enums used in requests/responses) are namespaced under `<Service>ClientTypes`: |
| 43 | |
| 44 | - `S3ClientTypes.Bucket`, `S3ClientTypes.Object` |
| 45 | - `DynamoDBClientTypes.AttributeValue` |
| 46 | - `CloudWatchClientTypes.MetricDatum`, `CloudWatchClientTypes.Dimension` |
| 47 | |
| 48 | ```swift |
| 49 | import AWSS3 |
| 50 | import AWSDynamoDB |
| 51 | |
| 52 | // Simple - auto-detects region |
| 53 | let s3 = try await S3Client() |
| 54 | let dynamo = try await DynamoDBClient() |
| 55 | |
| 56 | // With region |
| 57 | let s3 = try S3Client(region: "us-west-2") |
| 58 | |
| 59 | // With config - parameters must be in declaration order |
| 60 | let config = try await S3Client.S3ClientConfig( |
| 61 | useFIPS: true, |
| 62 | awsRetryMode: .adaptive, |
| 63 | maxAttempts: 5, |
| 64 | region: "us-west-2" |
| 65 | ) |
| 66 | let client = S3Client(config: config) |
| 67 | |
| 68 | // With custom endpoint and credentials |
| 69 | let config = try await S3Client.S3ClientConfig( |
| 70 | awsCredentialIdentityResolver: resolver, |
| 71 | region: "us-west-2", |
| 72 | endpoint: "https://s3.custom-endpoint.com" |
| 73 | ) |
| 74 | ``` |
| 75 | |
| 76 | Common config parameters (MUST follow declaration order): |
| 77 | |
| 78 | - `awsCredentialIdentityResolver` - Custom credentials |
| 79 | - `useFIPS` - Enable FIPS endpoints |
| 80 | - `useDualStack` - Enable dual-stack endpoints |
| 81 | - `awsRetryMode` - Retry strategy (.adaptive, .standard, .legacy) |
| 82 | - `maxAttempts` - Max retry attempts |
| 83 | - `region` - AWS region |
| 84 | - `httpClientEngine` - Custom HTTP client (requires HttpClientConfiguration parameter): |
| 85 | |
| 86 | ```swift |
| 87 | import ClientRuntime |
| 88 | let httpConfig = HttpClientConfiguration() |
| 89 | let httpClient = URLSessionHTTPClient(httpClientConfiguration: httpConfig) |
| 90 | let config = try await S3Client.S3ClientConfig( |
| 91 | region: "us-east-1", |
| 92 | httpClientEngine: httpClient |
| 93 | ) |
| 94 | ``` |
| 95 | |
| 96 | - `endpoint` - Custom endpoint URL |
| 97 | |
| 98 | For service-specific config options or exact parameter order, check `Sources/Services/AWS<Service>/Sources/AWS<Service>/<Service>Client.swift` in the SDK. |
| 99 | |
| 100 | ## Credential Resolvers |
| 101 | |
| 102 | ```swift |
| 103 | import AWSSDKIdentity |
| 104 | import SmithyIdentity |
| 105 | |
| 106 | // Static credentials - pass credential object directly |
| 107 | let creds = AWSCredentialIdentity(accessKey: "AKIA...", secret: "...") |
| 108 | let resolver = StaticAWSCredentialIdentityResolver(creds) |
| 109 | |
| 110 | // Assume role - REQUIRES underlying resolver |
| 111 | let underlying = try DefaultAWSCredentialIdentityResolverChain() |
| 112 | let resolver = try STSAssumeRoleAWSCredentialIdentityResolver( |
| 113 | awsCredentialIdentityResolver: underlying, |
| 114 | roleArn: "arn:aws:iam::123456789012:role/MyRole", |
| 115 | sessionName: "session-name" |
| 116 | ) |
| 117 | |
| 118 | // Use in config |
| 119 | let config = try await S3Client.S3ClientConfig( |
| 120 | awsCredentialIdentityResolver: resolver, |
| 121 | region: "us-west-2" |
| 122 | ) |
| 123 | ``` |
| 124 | |
| 125 | ## Waiters |
| 126 | |
| 127 | Import `SmithyWaitersAPI`. WaiterOptions requires `maxWaitTime` parameter: |
| 128 | |
| 129 | ```swift |
| 130 | import AWSS3 |
| 131 | import SmithyWaitersAPI |
| 132 | |
| 133 | let client = try await S3Client() |
| 134 | _ = try await client.waitUntilBucketExists( |
| 135 | options: WaiterOptions(maxWaitTime: 120.0), |
| 136 | input: HeadBucketInput(bucket: "my-bucket") |
| 137 | ) |
| 138 | ``` |
| 139 | |
| 140 | ## Pagination |
| 141 | |
| 142 | ```swift |
| 143 | let input = ListObjectsV2Input(bucket: "my-bucket") |
| 144 | for try await page in client.listObjectsV2Paginated(input: input) { |
| 145 | for object in page.contents ?? [] { |
| 146 | print(object.key ?? "") |
| 147 | } |
| 148 | } |
| 149 | ``` |
| 150 | |
| 151 | ## Presigned URLs |
| 152 | |
| 153 | ```swift |
| 154 | let url = try await client.presignedURLForGetObject( |
| 155 | input: GetObjectInput(bucket: "my-bucket", key: "file.pdf"), |
| 156 | expiration: 3600 |
| 157 | ) |
| 158 | ``` |
| 159 | |
| 160 | ## Common Operations |
| 161 | |
| 162 | ```swift |
| 163 | // Put object |
| 164 | _ = try await client.putObject(input: PutObjectInput( |
| 165 | body: .data(data), |
| 166 | bucket: "bucket", |
| 167 | key: "key" |
| 168 | )) |
| 169 | |
| 170 | // Get object |
| 171 | let output = try await client.getObject(input: GetObjectInput(bucket: "bucket", key: "key")) |
| 172 | let data = try await output.body?.readData() |
| 173 | |
| 174 | // List buckets |
| 175 | let response = try await client.listBuckets(input: ListBucketsInput()) |
| 176 | for bucket in response.buckets |