diff --git a/README.md b/README.md index 3e108ba..4e4b665 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,40 @@ docker compose run --rm -e SPRING_PROFILES_ACTIVE=dev,seed app ./mvnw compile exec:java -Dexec.mainClass=finance.idem.examples.basic.BasicTransactionExampleKt ``` +### Configuring `.env` + +Every example reads two variables — `IDEM_BASE_URL` and `IDEM_API_KEY` — via a +shared `requiredEnv()` helper +([`support/Env.kt`](src/main/kotlin/finance/idem/examples/support/Env.kt)) +backed by [`dotenv-kotlin`](https://github.com/cdimascio/dotenv-kotlin). It +loads `.env` from the project root automatically, so once the file is filled +in you can run any example directly — no manual `export`/`source` step +needed. A real environment variable, if set, always takes precedence over +the value in `.env`. + +`.env` is gitignored; `.env.example` is the checked-in template: + +```bash +cp .env.example .env +``` + +Then fill in: + +| Variable | Value | +|---|---| +| `IDEM_BASE_URL` | `http://localhost:8081` when running the stack via `docker compose up -d` above | +| `IDEM_API_KEY` | The key printed by the `docker compose run --rm -e SPRING_PROFILES_ACTIVE=dev,seed app` seed step | + +```bash +# .env +IDEM_BASE_URL=http://localhost:8081 +IDEM_API_KEY=sk_live_... # from the seed step's printed output +``` + +If `.env` is missing or a variable is blank, each example fails fast with +`IDEM_BASE_URL is not set — see .env.example` (or the equivalent for +`IDEM_API_KEY`) rather than a confusing SDK-level error. + ## Examples | # | Example | What it shows | diff --git a/pom.xml b/pom.xml index 5e7a0c9..9f80cd7 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,11 @@ kotlinx-coroutines-core 1.7.3 + + io.github.cdimascio + dotenv-kotlin + 6.5.1 + diff --git a/src/main/kotlin/finance/idem/examples/basic/BasicTransactionExample.kt b/src/main/kotlin/finance/idem/examples/basic/BasicTransactionExample.kt index 465d4ac..1955e1a 100644 --- a/src/main/kotlin/finance/idem/examples/basic/BasicTransactionExample.kt +++ b/src/main/kotlin/finance/idem/examples/basic/BasicTransactionExample.kt @@ -1,6 +1,7 @@ package finance.idem.examples.basic import finance.idem.examples.support.createAccount +import finance.idem.examples.support.requiredEnv import finance.idem.sdk.IdemClient import finance.idem.sdk.model.EntryType import finance.idem.sdk.model.FiatCurrency @@ -24,8 +25,8 @@ import java.util.UUID */ fun main() = runBlocking { - val baseUrl = System.getenv("IDEM_BASE_URL") ?: error("IDEM_BASE_URL is not set — see .env.example") - val apiKey = System.getenv("IDEM_API_KEY") ?: error("IDEM_API_KEY is not set — see .env.example") + val baseUrl = requiredEnv("IDEM_BASE_URL") + val apiKey = requiredEnv("IDEM_API_KEY") val client = IdemClient(baseUrl = baseUrl, apiKey = apiKey) client.use { diff --git a/src/main/kotlin/finance/idem/examples/mcp/McpAgentWorkflowExample.kt b/src/main/kotlin/finance/idem/examples/mcp/McpAgentWorkflowExample.kt index 86c8e6a..790e851 100644 --- a/src/main/kotlin/finance/idem/examples/mcp/McpAgentWorkflowExample.kt +++ b/src/main/kotlin/finance/idem/examples/mcp/McpAgentWorkflowExample.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import finance.idem.examples.support.allowAgentMaxDebitPerSession import finance.idem.examples.support.createAccount import finance.idem.examples.support.mintAgentApiKey +import finance.idem.examples.support.requiredEnv import finance.idem.sdk.IdemClient import io.modelcontextprotocol.client.McpClient import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport @@ -40,8 +41,8 @@ import java.util.UUID */ fun main() = runBlocking { - val baseUrl = System.getenv("IDEM_BASE_URL") ?: error("IDEM_BASE_URL is not set — see .env.example") - val apiKey = System.getenv("IDEM_API_KEY") ?: error("IDEM_API_KEY is not set — see .env.example") + val baseUrl = requiredEnv("IDEM_BASE_URL") + val apiKey = requiredEnv("IDEM_API_KEY") val objectMapper = ObjectMapper() val client = IdemClient(baseUrl = baseUrl, apiKey = apiKey) diff --git a/src/main/kotlin/finance/idem/examples/onchain/StablecoinOnChainExample.kt b/src/main/kotlin/finance/idem/examples/onchain/StablecoinOnChainExample.kt index 4169757..f05df95 100644 --- a/src/main/kotlin/finance/idem/examples/onchain/StablecoinOnChainExample.kt +++ b/src/main/kotlin/finance/idem/examples/onchain/StablecoinOnChainExample.kt @@ -1,6 +1,7 @@ package finance.idem.examples.onchain import finance.idem.examples.support.createAccount +import finance.idem.examples.support.requiredEnv import finance.idem.sdk.IdemClient import finance.idem.sdk.model.ChainId import finance.idem.sdk.model.EntryType @@ -39,8 +40,8 @@ import java.util.UUID */ fun main() = runBlocking { - val baseUrl = System.getenv("IDEM_BASE_URL") ?: error("IDEM_BASE_URL is not set — see .env.example") - val apiKey = System.getenv("IDEM_API_KEY") ?: error("IDEM_API_KEY is not set — see .env.example") + val baseUrl = requiredEnv("IDEM_BASE_URL") + val apiKey = requiredEnv("IDEM_API_KEY") val client = IdemClient(baseUrl = baseUrl, apiKey = apiKey) client.use { diff --git a/src/main/kotlin/finance/idem/examples/reconciliation/ReconciliationExample.kt b/src/main/kotlin/finance/idem/examples/reconciliation/ReconciliationExample.kt index 3528ea0..0421266 100644 --- a/src/main/kotlin/finance/idem/examples/reconciliation/ReconciliationExample.kt +++ b/src/main/kotlin/finance/idem/examples/reconciliation/ReconciliationExample.kt @@ -1,6 +1,7 @@ package finance.idem.examples.reconciliation import finance.idem.examples.support.createAccount +import finance.idem.examples.support.requiredEnv import finance.idem.sdk.IdemClient import finance.idem.sdk.model.ChainId import finance.idem.sdk.model.EntryType @@ -27,8 +28,8 @@ import java.util.UUID */ fun main() = runBlocking { - val baseUrl = System.getenv("IDEM_BASE_URL") ?: error("IDEM_BASE_URL is not set — see .env.example") - val apiKey = System.getenv("IDEM_API_KEY") ?: error("IDEM_API_KEY is not set — see .env.example") + val baseUrl = requiredEnv("IDEM_BASE_URL") + val apiKey = requiredEnv("IDEM_API_KEY") val client = IdemClient(baseUrl = baseUrl, apiKey = apiKey) client.use { diff --git a/src/main/kotlin/finance/idem/examples/settlement/PendingSettlementExample.kt b/src/main/kotlin/finance/idem/examples/settlement/PendingSettlementExample.kt index bcbbef0..633eb83 100644 --- a/src/main/kotlin/finance/idem/examples/settlement/PendingSettlementExample.kt +++ b/src/main/kotlin/finance/idem/examples/settlement/PendingSettlementExample.kt @@ -1,6 +1,7 @@ package finance.idem.examples.settlement import finance.idem.examples.support.createAccount +import finance.idem.examples.support.requiredEnv import finance.idem.sdk.IdemClient import finance.idem.sdk.model.ChainId import finance.idem.sdk.model.EntryType @@ -29,8 +30,8 @@ import java.util.UUID */ fun main() = runBlocking { - val baseUrl = System.getenv("IDEM_BASE_URL") ?: error("IDEM_BASE_URL is not set — see .env.example") - val apiKey = System.getenv("IDEM_API_KEY") ?: error("IDEM_API_KEY is not set — see .env.example") + val baseUrl = requiredEnv("IDEM_BASE_URL") + val apiKey = requiredEnv("IDEM_API_KEY") val client = IdemClient(baseUrl = baseUrl, apiKey = apiKey) client.use { diff --git a/src/main/kotlin/finance/idem/examples/support/Env.kt b/src/main/kotlin/finance/idem/examples/support/Env.kt new file mode 100644 index 0000000..b24963a --- /dev/null +++ b/src/main/kotlin/finance/idem/examples/support/Env.kt @@ -0,0 +1,17 @@ +package finance.idem.examples.support + +import io.github.cdimascio.dotenv.dotenv + +/** + * Loaded once per JVM. Host environment variables always take precedence + * over `.env` entries (dotenv-kotlin's own resolution order), so a real + * shell export still wins over a stale `.env` file. + */ +private val dotenv = dotenv { ignoreIfMissing = true } + +/** + * Resolves an environment variable from the host environment or `.env` + * (see `.env.example`), failing fast with a message pointing at the file + * every example relies on for local configuration. + */ +fun requiredEnv(key: String): String = dotenv[key] ?: error("$key is not set — see .env.example")