Creating a Go Command-Line Interface for Currency Conversion

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Project Setup
  4. Currency Conversion API
  5. Command-Line Interface
  6. Building the Application
  7. Conclusion

Introduction

In this tutorial, we will learn how to create a command-line interface (CLI) application in Go that performs currency conversion using an API. By the end of this tutorial, you will have a working CLI tool that can convert currency amounts between different currencies.

To follow along with this tutorial, you should have a basic understanding of the Go programming language, including variables, functions, and command-line arguments.

Prerequisites

Before starting this tutorial, make sure you have the following prerequisites:

  • Go installed on your machine (Download Go)
  • An API key for the currency conversion service. In this tutorial, we will use the Open Exchange Rates API. You can sign up for a free API key here.

Project Setup

To begin, let’s create a new directory for our project and initialize a Go module:

mkdir currency-converter-cli
cd currency-converter-cli
go mod init github.com/your-username/currency-converter-cli

Replace your-username with your own GitHub username or any other valid module identifier.

Next, let’s create a new Go file called main.go:

touch main.go

Open main.go in your favorite text editor.

Currency Conversion API

Before we start building the CLI, let’s first write the code to interact with the currency conversion API. In this example, we will use the Open Exchange Rates API.

First, we need to install a library to make HTTP requests. Run the following command in your project directory:

go get -u github.com/go-resty/resty/v2

In your main.go file, import the necessary packages:

package main

import (
	"encoding/json"
	"fmt"
	"github.com/go-resty/resty/v2"
)

Next, let’s define the data structures for the API response. Add the following struct definitions to main.go:

type LatestRatesResponse struct {
	Rates map[string]float64 `json:"rates"`
}

type ConvertResponse struct {
	Result float64 `json:"result"`
}

Now, let’s write a function to retrieve the latest exchange rates from the API. Add the following function to main.go:

func getLatestRates(apiKey string) (map[string]float64, error) {
	client := resty.New()

	response, err := client.R().
		SetQueryParam("app_id", apiKey).
		Get("https://openexchangerates.org/api/latest.json")

	if err != nil {
		return nil, err
	}

	var ratesResponse LatestRatesResponse
	err = json.Unmarshal(response.Body(), &ratesResponse)
	if err != nil {
		return nil, err
	}

	return ratesResponse.Rates, nil
}

In the function above, we use the resty package to send an HTTP GET request to the API endpoint. We pass the apiKey as a query parameter and handle the API response using the resty.Response struct. Finally, we parse the response body into our LatestRatesResponse struct and return the rates.

We will also need a function to perform the actual currency conversion. Add the following function to main.go:

func convertCurrency(apiKey, from, to string, amount float64) (float64, error) {
	client := resty.New()

	response, err := client.R().
		SetQueryParam("app_id", apiKey).
		SetQueryParam("from", from).
		SetQueryParam("to", to).
		SetQueryParam("amount", fmt.Sprintf("%f", amount)).
		Get("https://openexchangerates.org/api/convert")

	if err != nil {
		return 0, err
	}

	var convertResponse ConvertResponse
	err = json.Unmarshal(response.Body(), &convertResponse)
	if err != nil {
		return 0, err
	}

	return convertResponse.Result, nil
}

Here, we send an HTTP GET request to the conversion endpoint, passing the apiKey, source currency (from), target currency (to), and the amount to be converted. We parse the API response into our ConvertResponse struct and return the converted amount.

Now that we have the API interaction code in place, let’s move on to building the CLI interface.

Command-Line Interface

To create a user-friendly CLI, we will use the flag package to parse command-line arguments. Update your main.go file to import the flag package:

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/go-resty/resty/v2"
	"os"
)

We will define two subcommands for our CLI: rates (to get the latest exchange rates) and convert (to perform currency conversion).

Add the following code to main.go after the imports:

func main() {
	apiKey := flag.String("api-key", "", "API Key for currency conversion service")
	flag.Parse()

	if *apiKey == "" {
		fmt.Println("Please provide an API key using the -api-key flag")
		os.Exit(1)
	}

	if len(os.Args) < 2 {
		fmt.Println("Please provide a subcommand: rates, convert")
		os.Exit(1)
	}

	subcommand := os.Args[1]

	switch subcommand {
	case "rates":
		ratesCmd(*apiKey)
	case "convert":
		convertCmd(*apiKey)
	default:
		fmt.Println("Invalid subcommand")
		os.Exit(1)
	}
}

In the main function, we use the flag package to parse the -api-key flag provided by the user. If the flag is missing or empty, we print an error message and exit.

We then check the subcommand provided by the user (e.g., rates or convert) and call the corresponding function.

Let’s define the ratesCmd and convertCmd functions now.

Add the following code after the main function:

func ratesCmd(apiKey string) {
	rates, err := getLatestRates(apiKey)
	if err != nil {
		fmt.Println("Failed to retrieve exchange rates:", err)
		os.Exit(1)
	}

	fmt.Println("Exchange Rates:")
	for currency, rate := range rates {
		fmt.Printf("%s: %f\n", currency, rate)
	}
}

func convertCmd(apiKey string) {
	from := flag.String("from", "", "Source currency")
	to := flag.String("to", "", "Target currency")
	amount := flag.Float64("amount", 1, "Amount to convert")
	flag.Parse()

	if *from == "" || *to == "" {
		fmt.Println("Please provide both source and target currencies using the -from and -to flags")
		os.Exit(1)
	}

	convertedAmount, err := convertCurrency(apiKey, *from, *to, *amount)
	if err != nil {
		fmt.Println("Currency conversion failed:", err)
		os.Exit(1)
	}

	fmt.Printf("%f %s = %f %s\n", *amount, *from, convertedAmount, *to)
}

The ratesCmd function calls the getLatestRates function to retrieve the exchange rates and prints them on the screen.

The convertCmd function uses the flag package to parse the -from, -to, and -amount flags provided by the user. We check if the required flags are missing or empty and exit with an error message if they are. We then call the convertCurrency function to perform the conversion and print the result on the screen.

Building the Application

To build the application, run the following command in your project directory:

go build

This will create an executable file named currency-converter-cli.

Now, you can run the CLI tool and test the functionality. Here are a few examples:

# Get the latest exchange rates
./currency-converter-cli -api-key=<your-api-key> rates

# Convert 10 USD to EUR
./currency-converter-cli -api-key=<your-api-key> convert -from=USD -to=EUR -amount=10

# Convert 100 JPY to GBP
./currency-converter-cli -api-key=<your-api-key> convert -from=JPY -to=GBP -amount=100

Replace <your-api-key> with your actual API key.

Congratulations! You have created a Go command-line interface for currency conversion. Feel free to explore and enhance the application further, add error handling, or customize it to suit your specific needs.

Conclusion

In this tutorial, we learned how to create a command-line interface (CLI) application in Go for currency conversion. We covered the basics of interacting with a REST API, parsing command-line arguments using the flag package, and structuring the CLI application.

By following this tutorial, you should now have a good understanding of how to build simple CLI tools in Go and use them to perform useful tasks.

Remember to always consider error handling, test your code thoroughly, and document it properly to create robust and maintainable CLI applications.

Happy coding!