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

## Module Overview
The `com.github.blaxk3.api` module provides a thin HTTP client wrapper around the ExchangeRate-API service. It is responsible for loading the API key from `config.properties`, building request URLs, executing GET requests, and extracting currency metadata or conversion results from JSON responses.

The module is centered on a single service class, `CurrencyRateAPI`, which acts as the integration boundary between the application and the external exchange-rate provider. The class combines configuration lookup, request execution, and response parsing in one place, so its methods are closely coupled and should be read together.

---

## Class: CurrencyRateAPI

### Class Summary
| Field | Value |
|-------|-------|
| FQN | `com.github.blaxk3.api.CurrencyRateAPI` |
| Layer | API integration / external service client |
| Methods | 5 |

The source inventory reports 3 key methods for this module, but the class also contains two supporting methods (`getURL()` and `convert()`) that are part of the runtime behavior and are documented here for completeness.

### Method: getApiKeyService()

#### 1. Role
This method loads the external API key from the application classpath. It reads `config.properties`, extracts the `API_KEY` property, and returns it to callers that need to construct ExchangeRate-API requests.

If the configuration file is missing or cannot be loaded, the method logs an error and returns `null`. This makes it a critical configuration gate for every downstream API call.

#### 2. Processing Pattern
```mermaid
flowchart TD
    A["Start"] --> B["Create Properties container"]
    B --> C["Load config.properties from classpath"]
    C --> D{"Resource found?"}
    D -->|No| E["Log missing configuration"]
    E --> F["Return null"]
    D -->|Yes| G["Load properties from input stream"]
    G --> H{"Load succeeded?"}
    H -->|No| I["Log load error"]
    I --> F
    H -->|Yes| J["Read API_KEY property"]
    J --> K["Return API key"]
```

#### 3. Parameter Analysis
| Parameter | Type | Direction | Meaning |
|-----------|------|-----------|---------|
| None | — | — | The method does not accept input parameters |

#### 4. CRUD Operations / Called Services
| Dependency | Operation | Notes |
|------------|-----------|-------|
| Classpath resource `config.properties` | Read | Loads external configuration from the runtime resources |
| `Logger` | Create / Read | Writes error logs when configuration is unavailable or invalid |

#### 5. Dependency Trace
| Entry Point | Caller | Notes |
|------------|--------|-------|
| `getURL()` | Internal call | Uses the API key to build the base service URL |
| `getJsonObject(URL)` | Indirect chain | Depends on `getURL()` and therefore on this method's result |
| `getCurrencyCode()` | Indirect chain | Reaches this method through `getURL()` |
| `convert(String, String, BigDecimal)` | Indirect chain | Reaches this method through `getURL()` |

#### 6. Per-Branch Detail Blocks
- **Resource lookup branch**
  - If `getResourceAsStream("config.properties")` returns `null`, the method stops immediately after logging an error.
  - This branch protects the code from a downstream `NullPointerException` during property loading.
- **Successful load branch**
  - If the resource exists, the method loads all properties and returns the value mapped to `API_KEY`.
  - A missing `API_KEY` property still results in a `null` return value, even though the file was found.
- **Exception branch**
  - If an `IOException` occurs during `properties.load(input)`, the exception is logged and `null` is returned.
  - The method does not retry or apply a fallback configuration source.

---

### Method: getURL()

#### 1. Role
This method builds the base ExchangeRate-API URL by concatenating the service host with the API key returned by `getApiKeyService()`. It is a simple composition method used as the entry point for all API endpoint construction.

Because it delegates directly to the configuration loader, it inherits the availability of the resource file and the validity of the stored API key.

#### 3. Parameter Analysis
| Parameter | Type | Direction | Meaning |
|-----------|------|-----------|---------|
| None | — | — | The method does not accept input parameters |

#### 4. CRUD Operations / Called Services
| Dependency | Operation | Notes |
|------------|-----------|-------|
| `getApiKeyService()` | Read | Fetches the API key from configuration |
| String concatenation | Construct | Produces the base remote service URL |

#### 5. Dependency Trace
| Entry Point | Caller | Notes |
|------------|--------|-------|
| `getJsonObject(URL)` | Internal call chain | Uses the base URL for endpoint construction |
| `getCurrencyCode()` | Internal call chain | Builds the latest-rates endpoint from this base URL |
| `convert(String, String, BigDecimal)` | Internal call chain | Builds the pair-conversion endpoint from this base URL |

---

### Method: getJsonObject(URL url)

#### 1. Role
This method performs the actual HTTP GET request and parses the JSON response body into a `JsonObject`. It is the core transport-and-parse operation for the API integration layer.

The method returns `null` when the request fails, the response status is not `200 OK`, or any exception is raised while opening the connection or parsing the response.

#### 2. Processing Pattern
```mermaid
flowchart TD
    A["Start"] --> B["Open HttpURLConnection"]
    B --> C["Set request method to GET"]
    C --> D["Read response code"]
    D --> E{"Response code is 200"}
    E -->|No| F["Log failed response code"]
    F --> G["Return null"]
    E -->|Yes| H["Read response stream"]
    H --> I["Parse JSON with JsonParser"]
    I --> J["Convert root to JsonObject"]
    J --> K["Return JsonObject"]
    B --> L{"Exception thrown"}
    L -->|Yes| M["Log request error"]
    M --> G
```

#### 3. Parameter Analysis
| Parameter | Type | Direction | Meaning |
|-----------|------|-----------|---------|
| `url` | `URL` | In | Target endpoint to call over HTTP |

#### 4. CRUD Operations / Called Services
| Dependency | Operation | Notes |
|------------|-----------|-------|
| `HttpURLConnection` | Read | Executes an outbound GET request |
| `JsonParser` | Read | Parses the HTTP response body as JSON |
| `Logger` | Create / Read | Records non-200 responses and runtime errors |

#### 5. Dependency Trace
| Entry Point | Caller | Notes |
|------------|--------|-------|
| `getCurrencyCode()` | Direct call | Fetches the latest exchange-rate payload |
| `convert(String, String, BigDecimal)` | Direct call | Fetches pair conversion results |
| External callers | Public API | Any consumer can pass a `URL` and receive the parsed response |

#### 6. Per-Branch Detail Blocks
- **HTTP success branch**
  - The request is configured as `GET` before the response code is inspected.
  - Only `HTTP_OK` responses are parsed; the body is not read for any other status.
- **Non-OK branch**
  - The method logs the returned status code and returns `null`.
  - No exception is raised to the caller for non-200 responses, so the caller must handle `null`.
- **Exception branch**
  - Any exception during connection setup, response reading, or parsing is caught by the generic handler.
  - The method logs the failure and returns `null`, keeping the public API forgiving but requiring defensive null checks.

---

### Method: getCurrencyCode()

#### 1. Role
This method retrieves the set of available currency codes from the ExchangeRate-API latest-rates endpoint. It builds a USD-based request, reads the `conversion_rates` object, and returns the JSON object keys as a string array.

The method is useful for populating currency selectors or validating user input against the provider's supported currencies. If the response is missing or malformed, the method returns `null`.

#### 3. Parameter Analysis
| Parameter | Type | Direction | Meaning |
|-----------|------|-----------|---------|
| None | — | — | The method does not accept input parameters |

#### 4. CRUD Operations / Called Services
| Dependency | Operation | Notes |
|------------|-----------|-------|
| `getURL()` | Read | Supplies the API base URL |
| `getJsonObject(URL)` | Read | Retrieves and parses the latest-rates payload |
| `JsonObject` | Read | Extracts the `conversion_rates` object and its keys |

#### 5. Dependency Trace
| Entry Point | Caller | Notes |
|------------|--------|-------|
| External callers | Public API | UI or service code can call this method to obtain supported currency codes |
| `convert(String, String, BigDecimal)` | No direct dependency | Separate flow, not used internally |

#### 6. Per-Branch Detail Blocks
- **Valid payload branch**
  - The method checks both that the root object is non-null and that it contains `conversion_rates`.
  - It then converts the key set into a `String[]` using `toArray(new String[0])`.
- **Missing data branch**
  - If the response object is `null`, or if the `conversion_rates` node is absent, the method returns `null`.
  - If `conversion_rates` exists but is empty, the method also returns `null`.

---

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

#### 1. Role
This method performs a direct currency conversion between two currency codes using the ExchangeRate-API pair endpoint. It constructs a pair-specific URL, invokes the shared JSON retrieval logic, and extracts the `conversion_result` field as a string.

Unlike `getCurrencyCode()`, this method does not perform intermediate null checks on the returned JSON object before dereferencing the `conversion_result` node. As a result, it assumes the request succeeds and the payload contains the expected field.

#### 3. Parameter Analysis
| Parameter | Type | Direction | Meaning |
|-----------|------|-----------|---------|
| `foreignCurrency1` | `String` | In | Source currency code |
| `foreignCurrency2` | `String` | In | Target currency code |
| `amount` | `BigDecimal` | In | Amount to convert |

#### 4. CRUD Operations / Called Services
| Dependency | Operation | Notes |
|------------|-----------|-------|
| `getURL()` | Read | Supplies the base API URL |
| `getJsonObject(URL)` | Read | Retrieves the pair conversion response |
| ExchangeRate-API `/pair/` endpoint | Read | External conversion service |

#### 5. Dependency Trace
| Entry Point | Caller | Notes |
|------------|--------|-------|
| External callers | Public API | Used by UI or application logic to compute conversion values |

#### 6. Per-Branch Detail Blocks
- **Happy path branch**
  - The method constructs a `/pair/{from}/{to}/{amount}` endpoint and reads the `conversion_result` field from the JSON response.
  - The return value is the JSON string representation of the numeric result.
- **Failure behavior**
  - If `getJsonObject(...)` returns `null`, the method will throw a `NullPointerException` when dereferencing `get("conversion_result")`.
  - Any URL construction exceptions are declared to the caller via `MalformedURLException` and `URISyntaxException`.

---

## Cross-Class Collaboration
The module currently has a single class, so collaboration happens internally through method delegation rather than across multiple classes. The main control flow is:

1. Load API key from `config.properties`
2. Build the base service URL
3. Call the remote ExchangeRate-API endpoint
4. Parse the JSON response
5. Extract either currency codes or conversion results

---

## Risks and Design Notes
- The module relies on a single external configuration file and returns `null` when configuration is missing, so callers must handle absent credentials explicitly.
- `getJsonObject(URL)` centralizes network access but also hides many errors behind `null`, which can shift failure detection to later callers.
- `convert(...)` is less defensive than `getCurrencyCode()` and can fail with a null dereference if the remote service returns an unexpected payload.
- The module has no caching, retry logic, timeout tuning, or circuit-breaking behavior, so it is best suited for simple request/response usage rather than high-volume integration.
