问题
I'm working with AWS Amplify to develop an iOS application. I've added storage through S3 to host some assets and am trying to configure the application to download them. The only issue is that every example I see has the bucket name and path hardcoded, but because I have multiple environments and make new environments sometimes and each bucket has the environment name appended to it, I don't want to have to rewrite the bucket name each time.
For example if I'm in my test environment the bucket name might be assetsxxxxxx-test but if I switch to a new environment, I might be referencing assetsyyyyy-dev let's say.
The thing is the bucket name is referenced in the aswconfiguration.json file:
"S3TransferUtility": {
"Default": {
"Bucket": "assetsxxxxx-test",
"Region": "us-east-2"
}
}
So my question is how can I reference that bucket name programmatically so that when that field is rewritten when I switch environments, I won't have to change my code.
Thanks
回答1:
I am unclear what your using to build your Amplify resources (cloudformation, terrraform, ?console? etc) and in turn create your 'aswconfiguration.json file'. But it sound like you need to pass in a dynamic variable which is very achievable.
If your using a codepipeline, codebuild arrangement to deploy your resources and config file you could either use bash commands (sed or perl) during the codebuild stage to change the variable. Or a custom lambda to update the file contents and copy to S3, which you would then pass the dynamic variable into the environment variable paramter.
Normally if this was a cloudformation template you could use a Pseudo Parameter Reference !Sub command, and then the parameter would be declared early on and reference whatever environment it is, e.g.
"Bucket": "asssetsxxxxxx-${Environment}"
回答2:
I just had this same question. My solution was similar but not quite the same. First I created the Codable struct like this
import Foundation
struct AwsConfiguration: Codable {
struct S3TransferUtility : Codable {
private enum CodingKeys: String, CodingKey {
case defaultConfig = "Default"
}
struct DefaultConfig : Codable {
private enum CodingKeys: String, CodingKey {
case bucket = "Bucket"
case region = "Region"
}
var bucket: String
var region: String
}
var defaultConfig: DefaultConfig
}
private enum CodingKeys: String, CodingKey {
case s3TransferUtility = "S3TransferUtility"
}
var s3TransferUtility: S3TransferUtility
}
Then I have a DataHelper class defined
final class DataHelper {
static func load<T: Decodable>(_ filename: String, as type: T.Type = T.self) -> T {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
fatalError("Couldn't find \(filename) in main bundle.")
}
do {
data = try Data(contentsOf: file)
} catch {
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
do {
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
} catch {
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}
}
Then put awsconfiguration.json
in your test target.
Then you can write a unit test like so
func testReadAWSConfiguration() throws {
let config: AwsConfiguration = DataHelper.load("awsconfiguration.json")
print ("************config bucket: \(config.s3TransferUtility.defaultConfig.bucket) " +
"\n************config region: \(config.s3TransferUtility.defaultConfig.region)")
XCTAssertNotEqual("", config.s3TransferUtility.defaultConfig.bucket)
XCTAssertNotEqual("", config.s3TransferUtility.defaultConfig.region)
}
回答3:
I solved it. For anybody else wondering, I'm still not sure if there's a field built in to the AWS SDK, but I decided to parse the awsconfiguration.json file directly int a custom struct:
struct AWSConfigurationJSON: Codable{
let S3TransferUtility: S3TransferUtility
}
struct S3TransferUtility: Codable{
let Default: S3TransferUtilityDefault
}
struct S3TransferUtilityDefault: Codable{
let Bucket: String
let Region: String
}
and then I read the file and parsed the JSON.
if let path = Bundle.main.path(forResource: "awsconfiguration", ofType: "json") {
do{
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONDecoder().decode(AWSConfigurationJSON.self, from: data)
print(jsonResult.S3TransferUtility.Default.Bucket)
bucketPath = jsonResult.S3TransferUtility.Default.Bucket
}catch let e{
print("error \(e)")
bucketPath = ""
}
}else{
bucketPath = ""
}
来源:https://stackoverflow.com/questions/61281838/referencing-aws-s3-bucket-name-programmatically-instead-of-hardcoded