# (DD02) Module: com.github.blaxk3.api — Detailed Design [41 LOC]

## Module Overview
The `com.github.blaxk3.api` module provides a small HTTP integration layer for currency exchange-rate data. It is centered on a single API wrapper class that loads configuration, calls the external ExchangeRate API, parses JSON responses, and exposes currency codes and conversion results to higher layers such as the Swing UI.

The module is intentionally lightweight: it does not persist data, does not own domain models, and does not implement business rules beyond request construction and response extraction. Its main responsibility is to bridge configuration and remote API responses into simple Java types that the rest of the application can consume.

---

## Class: CurrencyRateAPI

### Class Summary
| Field | Value |
|-------|-------|
| FQN | `com.github.blaxk3.api.CurrencyRateAPI` |
| Layer | Integration / API client |
| Methods | 5 public methods in source, 3 key methods documented here |

### Class Role
`CurrencyRateAPI` acts as a thin client around the ExchangeRate API. It loads the API key from `config.properties`, builds request URLs, performs GET requests, parses JSON payloads, and exposes helper methods for retrieving supported currency codes and conversion results.

The class is used directly by the UI layer, especially the asynchronous currency-code loader and the conversion button handler. That makes it a boundary component between configuration, network I/O, and presentation logic.

### Dependencies
- `config.properties` on the application classpath for the `API_KEY` value.
- `https://v6.exchangerate-api.com` as the remote service endpoint.
- Gson (`JsonParser`, `JsonObject`, `JsonElement`) for JSON parsing.
- `HttpURLConnection` for HTTP transport.
- SLF4J for logging.
- `UI.CurrencyCode` and the conversion action in `UI` as primary consumers.

---

### Method: getApiKeyService()

#### 1. Role
This method resolves the API key required to access the ExchangeRate service. It reads `config.properties` from the classpath, extracts the `API_KEY` property, and returns it as a string.

If the configuration file is missing or cannot be loaded, the method logs the failure and returns `null`. That makes it a foundational configuration lookup for every API call in the class.

#### 3. Parameter Analysis
| Parameter | Type | Required | Meaning |
|-----------|------|----------|---------|
| None | - | - | The method reads configuration from the classpath without caller input. |

#### 4. CRUD Operations / Called Services
| Target | Operation | Notes |
|--------|-----------|-------|
| `config.properties` | R | Loads the resource stream and reads the `API_KEY` property. |
| SLF4J logger | C | Logs missing resource and I/O failures. |
| External API | - | Not called directly, but its authentication depends on this value. |

#### 5. Dependency Trace
| Caller | Path | Notes |
|--------|------|-------|
| `getURL()` | Internal | Uses the API key to build the service base URL. |
| `getCurrencyCode()` | Internal | Indirectly depends on this method through `getURL()`. |
| `convert(...)` | Internal | Indirectly depends on this method through `getURL()`. |
| `UI.CurrencyCode#doInBackground()` | External caller path | Uses `getCurrencyCode()`, which depends on this method. |

#### 6. Per-Branch Detail Blocks
- **Resource lookup branch**
  - If `config.properties` is found, the method enters the `try` block and attempts to load properties.
  - If the resource stream is `null`, the method logs an error and returns `null` immediately.
- **I/O failure branch**
  - If `properties.load(input)` throws `IOException`, the method logs the exception and returns `null`.
- **Successful resolution branch**
  - The `API_KEY` value is returned as-is without validation or trimming.

---

### Method: getJsonObject(URL url)

#### 1. Role
This method sends an HTTP GET request to a supplied URL and converts the successful response body into a Gson `JsonObject`. It is the main transport-and-parse utility for the class.

The method centralizes network access, response-code checking, and JSON decoding so that higher-level methods only need to assemble URLs and inspect the returned payload. On non-OK responses or exceptions, it logs the error and returns `null`.

#### 3. Parameter Analysis
| Parameter | Type | Required | Meaning |
|-----------|------|----------|---------|
| `url` | `URL` | Yes | Fully constructed endpoint to invoke. Must already include the API key and route. |

#### 4. CRUD Operations / Called Services
| Target | Operation | Notes |
|--------|-----------|-------|
| Remote ExchangeRate API | R | Opens a connection, sends `GET`, and reads the response body. |
| `HttpURLConnection` | R | Configures request method and reads response code and content. |
| Gson parser | R | Parses the response stream into a JSON tree. |
| SLF4J logger | C | Logs non-200 responses and exceptions. |

#### 5. Dependency Trace
| Caller | Path | Notes |
|--------|------|-------|
| `getCurrencyCode()` | Internal | Calls this method to fetch the latest USD rates. |
| `convert(...)` | Internal | Calls this method to fetch a pair conversion result. |
| `UI` conversion action | External caller path | Indirectly depends on this method through `convert(...)`. |
| `UI.CurrencyCode#doInBackground()` | External caller path | Indirectly depends on this method through `getCurrencyCode()`. |

#### 6. Per-Branch Detail Blocks
- **HTTP setup branch**
  - The method opens a connection and sets the request method to `GET` before sending the request.
- **Success branch**
  - When the response code equals `HTTP_OK`, the response stream is parsed with Gson and returned as a `JsonObject`.
- **Failure branch**
  - For any non-OK response, the method logs the status code and returns `null`.
- **Exception branch**
  - Any exception during connection, response retrieval, or parsing is caught, logged, and converted into a `null` result.

---

### Method: getCurrencyCode()

#### 1. Role
This method requests the latest USD exchange-rate snapshot and returns the available currency codes from the `conversion_rates` object. It is effectively a capability-discovery method for populating UI selection lists.

The method builds the `/latest/USD` endpoint, delegates the HTTP call to `getJsonObject(URL)`, and then extracts the JSON object keys as a `String[]`. If the expected JSON shape is missing or empty, it returns `null`.

#### 3. Parameter Analysis
| Parameter | Type | Required | Meaning |
|-----------|------|----------|---------|
| None | - | - | The method always queries the USD base endpoint and returns all discovered codes. |

#### 4. CRUD Operations / Called Services
| Target | Operation | Notes |
|--------|-----------|-------|
| External ExchangeRate API | R | Retrieves the latest USD rates payload. |
| `getURL()` | C | Constructs the base service URL with the API key. |
| `getJsonObject(URL)` | R | Performs the HTTP request and JSON parsing. |
| JSON `conversion_rates` object | R | Reads keys only; no mutation occurs. |

#### 5. Dependency Trace
| Caller | Path | Notes |
|--------|------|-------|
| `UI.CurrencyCode#doInBackground()` | Direct external caller | Loads the array used to populate currency combo boxes. |
| `button()` in `UI` | Indirect caller path | The Convert button relies on combo boxes populated from this method. |

#### 6. Per-Branch Detail Blocks
- **Payload present branch**
  - If the response object is non-null and contains `conversion_rates`, the method reads that nested object.
  - If the nested object exists and has at least one key, the keys are converted to a `String[]` and returned.
- **Missing or empty branch**
  - If the root payload is `null`, lacks `conversion_rates`, or the nested object has no keys, the method returns `null`.
- **Exception surface**
  - URL construction can throw `MalformedURLException` or `URISyntaxException`, so callers must handle these checked exceptions.

---

### Method: convert(String foreignCurrency1, String foreignCurrency2, BigDecimal amount)

#### 1. Role
This method converts an amount from one currency to another by calling the ExchangeRate pair endpoint and extracting the `conversion_result` field. It is the primary user-facing operation of the API client.

The method is called from the UI conversion action, where user-entered amounts and selected currency codes are passed in. Unlike the other methods, it assumes the response contains `conversion_result` and does not perform defensive null checks before dereferencing the JSON payload.

#### 3. Parameter Analysis
| Parameter | Type | Required | Meaning |
|-----------|------|----------|---------|
| `foreignCurrency1` | `String` | Yes | Source currency code, for example `USD`. |
| `foreignCurrency2` | `String` | Yes | Target currency code, for example `EUR`. |
| `amount` | `BigDecimal` | Yes | Amount to convert. Serialized directly into the request URL. |

#### 4. CRUD Operations / Called Services
| Target | Operation | Notes |
|--------|-----------|-------|
| External ExchangeRate API | R | Calls the pair conversion endpoint. |
| `getURL()` | C | Supplies the authenticated base URL. |
| `getJsonObject(URL)` | R | Executes the request and parses the JSON response. |
| JSON `conversion_result` field | R | Reads the converted amount and returns it as a string. |

#### 5. Dependency Trace
| Caller | Path | Notes |
|--------|------|-------|
| `UI.button()` convert action | Direct external caller | Uses the result to update the displayed label. |
| End user input | Entry point | The selected currencies and amount flow from the UI into this method. |

#### 6. Per-Branch Detail Blocks
- **Request construction branch**
  - The method builds a pair URL using both currency codes and the amount value.
- **Success path**
  - A successful JSON response is expected to contain `conversion_result`; the method returns that value via `toString()`.
- **Failure sensitivity**
  - If `getJsonObject(URL)` returns `null`, this method will throw a `NullPointerException` when accessing `get("conversion_result")`.
  - Checked exceptions from URI/URL creation are propagated to the caller.

---

## Cross-Class Interaction Summary
- `UI.CurrencyCode` calls `CurrencyRateAPI.getCurrencyCode()` to populate currency combo boxes.
- The UI convert action calls `CurrencyRateAPI.convert(...)` to calculate and display exchange results.
- `CurrencyRateAPI` is therefore the only integration point in the module, and the UI layer depends on it for both data discovery and conversion.

## Design Notes
- The class uses direct HTTP access rather than a higher-level client library.
- Configuration is hard-coded to `config.properties` on the classpath and expects a single `API_KEY` property.
- Error handling is intentionally simple: log and return `null` for recoverable failures.
- The module currently has no caching, retry policy, or rate-limit handling.

## Risks and Constraints
- Missing configuration leads to `null` API keys and failed downstream requests.
- `convert(...)` does not guard against a null JSON response, so a failed API call can surface as a runtime exception.
- The class is coupled to the exact JSON structure returned by the ExchangeRate service.
- Because this module performs live network I/O, its behavior depends on external service availability and internet access.
