Refactoring a Currency Converter: Secure API Keys and Universal Conversions

Introduction

The ConversorDeMonedas project began as a straightforward Java application for currency conversion. While functional, it faced common challenges associated with rapid development: a hardcoded API key directly embedded in the source code, and a rigid design that limited conversions to specific pairs, such as USD to others. These limitations introduced security vulnerabilities and hindered the application's extensibility.

The Problem with Monolithic Design and Exposed Secrets

Hardcoding sensitive information like API keys is a significant security risk. When committed to version control, it exposes credentials to anyone with access to the repository, potentially leading to misuse. Furthermore, a tightly coupled design, where API calls, parsing logic, and user interaction are intertwined, makes it difficult to introduce new features, like supporting arbitrary currency pairs, or to maintain the codebase efficiently.

Modularizing for Flexibility and Security

The refactoring effort focused on addressing these issues by adopting a more modular and secure architecture. Key components were introduced to separate concerns:

  • ConsultaAPI.java: This class was created to encapsulate all logic related to external API interaction. It's responsible for constructing dynamic API URLs based on user input, securely loading the API key, making HTTP requests, and parsing the JSON response using Gson.
  • GeneradorDeArchivo.java: Dedicated to data persistence, this component centralizes the logic for saving conversion history. It ensures that each conversion, along with a timestamp and relevant details, is written to a file (e.g., tasas.txt).
  • Main.java: The main application class was refactored to act as an orchestrator. It manages user interaction, delegates API calls to ConsultaAPI, and uses GeneradorDeArchivo to persist the results. This clear separation makes the Main class more readable and maintainable.

Implementing Secure API Key Handling

To prevent the API key from being exposed in the source code, a crucial change was to externalize it into a config.properties file. This file is then excluded from version control using .gitignore. The ConsultaAPI class is responsible for loading this key at runtime.

Here's an illustrative example of how an API key might be loaded from a config.properties file:

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class ApiKeyLoader {
    public static String loadApiKey() {
        Properties prop = new Properties();
        try (FileInputStream fis = new FileInputStream("config.properties")) {
            prop.load(fis);
            return prop.getProperty("API_KEY");
        } catch (IOException ex) {
            System.err.println("Error loading API key: " + ex.getMessage());
            // In a real application, handle this more robustly, e.g., throw a custom exception
            return null;
        }
    }
}

This snippet demonstrates how ConsultaAPI can safely retrieve the API_KEY from config.properties without embedding it directly in the Java code, enhancing security and allowing for easy updates to the key without code changes.

Achieving Universal Conversion Capabilities

The refactoring enabled the ConversorDeMonedas application to support conversions between any currency pair offered by the external API. By dynamically constructing the API request URL using the base currency provided by the user (e.g., https://example.com/api/latest/{BASE_CURRENCY}), the application is no longer limited to hardcoded USD conversions. The Gson library then efficiently parses the JSON response, allowing the application to extract exchange rates for various target currencies.

Actionable Takeaways

When developing applications that interact with external services, always prioritize security and maintainability. Separate sensitive configurations into external files (e.g., config.properties) and ensure they are excluded from version control. Embrace modular design patterns to encapsulate concerns like API interaction and data persistence. This approach not only strengthens security but also makes your application more flexible, easier to extend, and simpler to maintain over time.


Generated with Gitvlg.com

Refactoring a Currency Converter: Secure API Keys and Universal Conversions
Laura Daniela Paucara Cusi

Laura Daniela Paucara Cusi

Author

Share: