# Com / Github / Blaxk3 / Api

## Overview

This module provides a Java client wrapper around the [ExchangeRate API](https://www.exchangerate-api.com/) (v6) for retrieving currency conversion rates and performing currency conversions. It is a single-class package (`CurrencyRateAPI`) that handles API key management, HTTP request construction, JSON response parsing, and conversion logic — serving as the integration point between the broader application and the external exchange rate service.

## Key Classes

### CurrencyRateAPI

**Source:** [CurrencyRateAPI.java](src/main/java/com/github/blaxk3/api/CurrencyRateAPI.java)

The `CurrencyRateAPI` class is the sole class in this package and the primary entry point for all interactions with the ExchangeRate API. It encapsulates API key loading from a properties file, URL assembly, HTTP communication, and JSON response handling.

#### Constructor and Dependencies

No explicit constructor is defined — the class relies on the default no-arg constructor. It depends on:

- **Gson** (`com.google.gson`) — for parsing JSON responses from the API into `JsonObject` structures.
- **SLF4J** (`org.slf4j.Logger`) — for structured logging of errors during config loading and HTTP requests.
- **Java standard library** — `Properties`, `InputStream`, `HttpURLConnection`, `BigDecimal`, `URL`, and `URISyntaxException`.

#### Method Details

##### getApiKeyService()

Loads the API key from `config.properties` (expected on the classpath at `config.properties`).

- **Parameters:** None.
- **Returns:** The string value of the `API_KEY` property, or `null` if the file is missing or an I/O error occurs.
- **Behavior:** Uses try-with-resources to safely open and close the `InputStream`. Logs an error if `config.properties` is not found on the classpath, or if any `IOException` occurs during loading.

This is a foundational method — every other API interaction routes through it to assemble the authenticated base URL.

##### getURL()

Assembles the base URL for the ExchangeRate API v6.

- **Parameters:** None.
- **Returns:** A `String` in the form `https://v6.exchangerate-api.com/v6/{apiKey}`, or `null` if the API key is unavailable.
- **Behavior:** Delegates to `getApiKeyService()` to obtain the key, then appends it to the fixed endpoint prefix.

##### getJsonObject(URL url)

Sends an HTTP GET request to the given URL and parses the JSON response into a `JsonObject`.

- **Parameters:** `url` — the endpoint to call (e.g. `latest/USD` or `pair/USD/EUR/100`).
- **Returns:** A `JsonObject` on success, or `null` if the request fails (non-200 response code or an exception).
- **Side effects:** Opens an `HttpURLConnection`, sets the method to `GET`, and reads from the response's `getContent()` stream. Logs the HTTP response code on failure, or a generic error message if an exception is thrown.
- **Important:** This method accesses `HttpURLConnection.getContent()` directly rather than calling `getInputStream()`. This works because the ExchangeRate API returns `application/json`, which `getContent()` handles. However, it is worth noting that `getContent()` is a lower-level method than `getInputStream()` and assumes the content type is already known.

##### getCurrencyCode()

Retrieves all available currency codes from the ExchangeRate API by querying the `latest/USD` endpoint.

- **Parameters:** None.
- **Returns:** A `String[]` containing all currency code keys (e.g. `["USD", "EUR", "GBP", ...]`), or `null` if the response is missing or the `conversion_rates` field is absent.
- **Throws:** `MalformedURLException`, `URISyntaxException` — from URL construction when combining the base URL with `/latest/USD`.
- **Behavior:** Calls `getJsonObject()` with the `/latest/USD` endpoint, extracts the `conversion_rates` JSON object, and returns the set of its keys as a string array.

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

Performs a currency conversion between two currencies for a given amount.

- **Parameters:**
  - `foreignCurrency1` — the source currency code (e.g. `"USD"`).
  - `foreignCurrency2` — the target currency code (e.g. `"EUR"`).
  - `amount` — the amount to convert, as a `BigDecimal` for precision.
- **Returns:** A `String` representing the converted amount (e.g. `"85.50"`), or `null` if the API request fails or the response lacks a `conversion_result` field.
- **Throws:** `MalformedURLException`, `URISyntaxException` — from URL construction when building the `/pair/` endpoint URL.
- **Behavior:** Constructs the `/pair/{from}/{to}/{amount}` endpoint URL, retrieves the JSON response, and extracts the `conversion_result` field. Returns it as a raw string.

## How It Works

The module follows a straightforward request-response pattern for all API interactions:

```mermaid
flowchart TD
    Client["Client / Caller"] --> getApiKeyService["getApiKeyService()"]
    getApiKeyService --> config["config.properties
(API_KEY)"]
    Client --> getURL["getURL()"]
    getURL --> getApiKeyService
    Client --> getJsonObject["getJsonObject(URL)"]
    getJsonObject --> http["HttpURLConnection
GET request"]
    http --> jsonResponse["JSON response
(JsonObject)"]
    Client --> getCurrencyCode["getCurrencyCode()"]
    getCurrencyCode --> latestEndpoint["latest/USD endpoint"]
    latestEndpoint --> conversionRates["conversion_rates object"]
    conversionRates --> codes["String[] currency codes"]
    Client --> convert["convert(from, to, amount)"]
    convert --> pairEndpoint["pair/XXX/YYY/amount endpoint"]
    pairEndpoint --> result["conversion_result value"]
```

**Flow 1 — Getting available currency codes (`getCurrencyCode`)**

1. The caller invokes `getCurrencyCode()`.
2. The method builds the URL: `https://v6.exchangerate-api.com/v6/{apiKey}/latest/USD`.
3. `getJsonObject()` opens an HTTP GET connection, sends the request, and expects an HTTP 200 response.
4. The JSON response is parsed; the `conversion_rates` sub-object is extracted.
5. The keys of that object (ISO 4217 currency codes like `"USD"`, `"EUR"`, `"GBP"`) are returned as a string array.

**Flow 2 — Currency conversion (`convert`)**

1. The caller invokes `convert("USD", "EUR", new BigDecimal("100"))`.
2. The method builds the URL: `https://v6.exchangerate-api.com/v6/{apiKey}/pair/USD/EUR/100`.
3. `getJsonObject()` performs the GET request and parses the JSON response.
4. The `conversion_result` field is extracted from the response and returned as a string (e.g. `"85.50"`).

## Data Model

This module does not define its own entity classes or DTOs. It works directly with types from the Java standard library and Gson:

| Type | Source | Purpose |
|------|--------|---------|
| `String` | Java | API key, currency codes, URL, converted amount |
| `BigDecimal` | Java | Precise monetary amounts for conversion |
| `String[]` | Java | Array of currency codes returned by `getCurrencyCode()` |
| `JsonObject` | Gson | Parsed JSON response from the ExchangeRate API |
| `Properties` | Java | Configuration file (`config.properties`) containing the API key |

### Expected API Response Shapes

**`/latest/USD` response** (used by `getCurrencyCode`):

```json
{
  "conversion_rates": {
    "USD": 1,
    "EUR": 0.92,
    "GBP": 0.79,
    ...
  }
}
```

**`/pair/USD/EUR/100` response** (used by `convert`):

```json
{
  "conversion_result": "85.50",
  ...
}
```

## Dependencies and Integration

### External Dependency

- **ExchangeRate API (v6)** — The module communicates with `https://v6.exchangerate-api.com/v6/` via HTTP GET. An API key is required, which must be placed in `config.properties` on the application classpath under the property name `API_KEY`.

### Java Dependencies

The module relies on these libraries (inferred from imports):

| Library | Usage |
|---------|-------|
| **Gson** (`com.google.gson`) | JSON parsing via `JsonParser`, `JsonElement`, `JsonObject` |
| **SLF4J** | Structured logging via `Logger` and `LoggerFactory` |

### Internal Dependencies

This package has no known cross-module dependencies — it operates as a self-contained client.

## Notes for Developers

### Configuration

- The API key must be present in `config.properties` on the classpath. If the file is missing or the `API_KEY` property is absent, `getApiKeyService()` returns `null`, which propagates to all downstream calls. Inspect the logs for the `"Unable to find config.properties"` error message to diagnose this.

### Error Handling

- `getJsonObject()` returns `null` on any failure (non-200 status code or exception). Callers must check for `null` before proceeding.
- `getCurrencyCode()` and `convert()` both propagate `MalformedURLException` and `URISyntaxException` — callers are expected to handle these checked exceptions.
- Logging is the only side-effect on error paths. No exceptions are thrown from `getJsonObject()` itself.

### Concurrency

The class has no state other than the logger (which is `static` and thread-safe), so instances are safe to use from multiple threads. However, each call opens a new `HttpURLConnection`, so under high load, consider connection pooling or connection reuse at a higher level.

### Precision

The `convert()` method accepts a `BigDecimal` for the amount (good practice for financial calculations), but returns the result as a `String` rather than a `BigDecimal`. If numeric precision is needed downstream, callers should parse the returned string back into a `BigDecimal`.

### Extension Points

The `getJsonObject()` method is the natural hook for adding features such as:
- Adding retry logic for transient network failures.
- Adding timeout configuration on the `HttpURLConnection`.
- Adding custom headers (e.g., for API versioning or user-agent).
- Supporting different API endpoints (e.g., historical rates, time-series) by extending the URL template patterns in `getCurrencyCode()` and `convert()`.

### URL Construction

URLs are built by string concatenation in `getURL()` and the two public methods that call it. This is simple and works for the known endpoint patterns, but would need care if new endpoint segments containing user-controlled input are added (to ensure proper encoding).
