Creating a Go-Based Command-Line Weather App

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setting Up
  4. Building the Weather App
  5. Conclusion

Introduction

In this tutorial, we will be creating a Go-based command-line weather app. The app will allow users to retrieve weather information for a specific location by making API requests. By the end of the tutorial, you will have a functional weather app that can be used from the command line.

Prerequisites

Before starting this tutorial, you should have a basic understanding of the Go programming language. Familiarity with concepts such as functions, variables, and API requests will be helpful. You will also need to have Go installed on your system.

Setting Up

To begin, let’s set up a new Go project. Open your terminal and create a new directory for the project:

mkdir weather-app
cd weather-app

Next, initialize a new Go module:

go mod init github.com/your-username/weather-app

We will be using a third-party library called “cobra” for building the command-line interface. Install it by running the following command:

go get -u github.com/spf13/cobra/cobra

Now, let’s create the main file for our project:

touch main.go

Open main.go in a text editor and import the required packages:

package main

import (
	"fmt"
	"github.com/spf13/cobra"
)

Building the Weather App

Now that we have set up the project, let’s start building the command-line weather app. We will be using the OpenWeatherMap API to retrieve weather data.

Step 1: Define the CLI Commands and Flags

First, let’s define the CLI commands and flags using the “cobra” library. Modify main.go as follows:

package main

import (
	"fmt"
	"github.com/spf13/cobra"
)

func main() {
	var rootCmd = &cobra.Command{
		Use:   "weather",
		Short: "A command-line weather app",
		Long:  "A command-line weather app that retrieves weather information for a specific location.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Welcome to the Weather App!")
		},
	}

	var versionCmd = &cobra.Command{
		Use:   "version",
		Short: "Print the version number of the Weather App",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Weather App v1.0")
		},
	}

	var city string
	var apiKey string

	var currentWeatherCmd = &cobra.Command{
		Use:   "current",
		Short: "Get the current weather for a specific city",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Retrieving current weather information for %s...\n", city)
			// Implement API request logic here
		},
	}

	currentWeatherCmd.Flags().StringVarP(&city, "city", "c", "", "Specify the city")
	currentWeatherCmd.Flags().StringVarP(&apiKey, "apikey", "k", "", "Specify the API key")

	rootCmd.AddCommand(versionCmd)
	rootCmd.AddCommand(currentWeatherCmd)

	rootCmd.Execute()
}

In the above code, we have defined three commands: version, current, and the default root command. The version command prints the version number of our app. The current command retrieves the current weather information for a specific city.

The current command accepts two flags: --city (or -c) to specify the city and --apikey (or -k) to provide the OpenWeatherMap API key.

Step 2: Make API Requests

Next, let’s implement the logic to make API requests and retrieve weather information.

We will be using the http package to make HTTP GET requests. Import the package at the top of the main.go file:

import (
	"fmt"
	"github.com/spf13/cobra"
	"io/ioutil"
	"net/http"
)

Add the following code inside the Run function of the currentWeatherCmd command:

func(cmd *cobra.Command, args []string) {
	fmt.Printf("Retrieving current weather information for %s...\n", city)

	url := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s", city, apiKey)

	response, err := http.Get(url)
	if err != nil {
		fmt.Println("Error making API request:", err)
		return
	}
	defer response.Body.Close()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Println("Error reading API response:", err)
		return
	}

	fmt.Println("API response:", string(body))
}

In the above code, we use fmt.Sprintf to construct the API URL using the provided city and API key. Then, we use http.Get to make a GET request to the API URL. We read the response body using ioutil.ReadAll and print it to the console.

Step 3: Handling Errors

Let’s enhance our code to handle errors gracefully. Replace the existing code inside the currentWeatherCmd.Run function with the following:

func(cmd *cobra.Command, args []string) {
	fmt.Printf("Retrieving current weather information for %s...\n", city)

	url := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s", city, apiKey)

	response, err := http.Get(url)
	if err != nil {
		fmt.Println("Error making API request:", err)
		return
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		fmt.Println("API request failed with status code:", response.StatusCode)
		return
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Println("Error reading API response:", err)
		return
	}

	fmt.Println("API response:", string(body))
}

In the updated code, we check the HTTP status code of the API response. If it is not 200 (OK), we print an error message. This helps us handle cases where the API request itself was successful, but the response indicates an error.

Conclusion

In this tutorial, we have created a Go-based command-line weather app using the “cobra” library. We explored how to define CLI commands and flags, make API requests, and handle errors. You should now have a functional weather app that can be used from the command line.

Feel free to expand on this app by adding more features, such as forecast information or additional command-line options. Happy coding!