Referencing AWS S3 bucket name programmatically instead of hardcoded

六眼飞鱼酱① 提交于 2021-02-11 15:23:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!