Does anyone have any good workflows to create V2 A...
# http4k
a
Does anyone have any good workflows to create V2 AWS SDKs with a factory function like this?
Copy code
fun createApp(env: Environment, internet: HttpHandler): HttpHandler {
  val sns = SnsClient.builder()
    .httpClient(AwsSdkClient(internet))
    // credentials, etc
    .build()

  return routes(...)
}
The problem is when I init with a test environment, I have no nice way of getting the aws credentials from the http4k
Environment
into the
EnvironmentVariableCredentialsProvider
. Ideally I would be able to continue working with the
DefaultAWSCredentialsProviderChain
rather than override it. If no one has a good workflow for this, it may just require some additional tooling in the
http4k-aws
module. Right now, my workaround is to add an optional
AwsCredentialsProvider
argument to my factory function, which the test environment can overload.
s
I tend to use
Environment
to drive which credential provider I need for different contexts (local vs build vs production). Something like:
Copy code
val CREDENTIALS_PROVIDER by EnvironmentKey.enum<SupportedCredentialsProvider>().of().defaulted(ContainerCredentials)
The
SupportedCredentialsProvider
looks like:
Copy code
enum class SupportedCredentialsProvider {
    ContainerCredentials {
        override fun invoke(env: Environment, http: HttpHandler, clock: Clock): CredentialsProvider =
            CredentialsProvider.ContainerCredentials(env, http, clock)
    },
    Profile {
        override fun invoke(env: Environment, http: HttpHandler, clock: Clock) =
            CredentialsProvider { CredentialsChain.Profile(env)() ?: error("could not find credentials") }
    };

    abstract operator fun invoke(
        env: Environment,
        http: HttpHandler,
        clock: Clock
    ): CredentialsProvider
}
We could turn that into an equivalent CredentialsProviderChain, I suppose.
j
We do something a bit similar... use a "well known" session credentials file which is enabled only when an environment variable "FALLBACK TO SESSION_CREDENTIALS FOR LOCAL TESTING" is set, otherwise just use container credentials. this uses the form:
Copy code
return CredentialsChain.Profile(
    profileName = ProfileName.of("temporary"),
    credentialsPath = ".../session-credentials.txt"
).provider()
so it will never pick up any identity from your "normal" aws credentials - its separate from the command line calls. This means you can't accidentally switch profiles in the CLI and then run a test that does something. not sure that this is "perfect", but it has helped us avoid some issues of picking up the currently selected cli id. To update, you get an access_key/secret/session token from sts however you normally do.
ah sorry - i missed the bit about using the aws sdk. i try not to!
mine looks similar:
Copy code
CredentialsChain.Environment(environment)
        .orElse(CredentialsChain.ContainerCredentials(environment, httpClient, clock))
        .let {
            when {
                environment.shouldUseSessionCredentialsFile -> {
                    println("WARNING - using session credentials file from [$sessionCredentialsProfileName] in $sessionCredentialsFilename")
                    AwsLocalTesting.awsSessionCredentialsForManualTests(sessionCredentialsFilename, sessionCredentialsProfileName)
                }
                else -> it
            }
        }
note passing in httpclient and clock, so can configure all the logging / tracing etc on it, but basically the same. 👍
a
Ivan's solution might be best if I don't want to be injecting overrides into the factory function.