Step 6 : Understanding the Raw JSON Data from OpenWeather API

When you make a request to the OpenWeather API, the data you receive is in JSON format. JSON is a common data format used for exchanging information between a client and a server . However, it’s not always easy to read directly, especially when dealing with weather data.


Let’s take a look at what theraw datalooks like when you request the weather information :


Example of Raw JSON Response :


{
    "name": "Paris",
    "weather": [
        {
            "description": "cloudy"
        }
    ],
    "main": {
        "temp": 20.07,
        "humidity": 27
    },
    "wind": {
        "speed": 6.37
    },
    "sys": {
        "sunrise": 1743397954,
        "sunset": 1743443005
    }
}
                      
                

What does this data represent?


Why is this raw JSON not easy to read?

The data is structured in a way that might be difficult for the user to understand directly. For example :


Example Code to Display Raw JSON in Go :

Now, let’s look at how we can fetch and display this raw JSON data in Go. Below is an example of a Go program that fetches the weather data from the OpenWeather API and prints out the raw JSON response.


package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"github.com/joho/godotenv"
)

type WeatherResponse struct {
	Name    string `json:"name"`
	Weather []struct {
		Description string `json:"description"`
	} `json:"weather"`
	Main struct {
		Temp     float64 `json:"temp"`
		Humidity int     `json:"humidity"`
	} `json:"main"`
	Wind struct {
		Speed float64 `json:"speed"`
	} `json:"wind"`
	Sys struct {
		Sunrise int64 `json:"sunrise"`
		Sunset  int64 `json:"sunset"`
	} `json:"sys"`
}

func main() {
	// Load environment variables from .env file
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}

	// Get the API key from environment variables
	apiKey := os.Getenv("API_KEY")
	if apiKey == "" {
		log.Fatal("API_KEY is not set in .env file")
	}

	// Ask the user for a city name
	var city string
	fmt.Println("Enter the name of the city:")
	fmt.Scanln(&city)

	// Build the request URL
	url := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric&lang=fr", city, apiKey)

	// Send the HTTP request
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal("Error sending request to OpenWeather API:", err)
	}
	defer resp.Body.Close()

	// Check if the response is valid (HTTP status code 200)
	if resp.StatusCode != 200 {
		log.Fatalf("Error: API status code = %d", resp.StatusCode)
	}

	// Decode the JSON response into the WeatherResponse struct
	var weatherData WeatherResponse
	err = json.NewDecoder(resp.Body).Decode(&weatherData)
	if err != nil {
		log.Fatal("Error decoding JSON response:", err)
	}

	// Print out the raw JSON for inspection
	fmt.Println("Raw JSON Response:")
	weatherJson, _ := json.MarshalIndent(weatherData, "", "  ")
	fmt.Println(string(weatherJson))
}

                

What does this code do?

copie this code in yourmain.gofile and excute it :

go run main.go

You should see something like this :

Enter the name of the city:
    Paris
    Raw JSON Response:
    {
      "name": "Paris",
      "weather": [
        {
          "description": "ciel dégagé"
        }
      ],
      "main": {
        "temp": 10.82,
        "humidity": 57
      },
      "wind": {
        "speed": 7.2
      },
      "sys": {
        "sunrise": 1743571556,
        "sunset": 1743618122
      }
    }
Step 7 : Improving the Display and Error Messages

In the previous step, we displayed the raw JSON response from the OpenWeather API . However, while this data is useful, it's not very user-friendly. In this step, we will improve :

Improving the Weather Display :

Instead of printing raw JSON, we will extract and format the important details in a way that is easier to understand.

Here’s how we can improve the output :


package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/joho/godotenv"
)

// Struct to store the weather API response
type WeatherResponse struct {
	Name    string `json:"name"`
	Weather []struct {
		Description string `json:"description"`
	} `json:"weather"`
	Main struct {
		Temp     float64 `json:"temp"`
		Humidity int     `json:"humidity"`
	} `json:"main"`
	Wind struct {
		Speed float64 `json:"speed"`
	} `json:"wind"`
	Sys struct {
		Sunrise int64 `json:"sunrise"`
		Sunset  int64 `json:"sunset"`
	} `json:"sys"`
}

func main() {
	// Load the .env file
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error: Unable to load .env file. Make sure it exists and contains your API key.")
	}

	// Retrieve the API key from environment variables
	apiKey := os.Getenv("API_KEY")
	if apiKey == "" {
		log.Fatal("Error: API_KEY is missing. Please check your .env file.")
	}

	// Ask the user for a city name
	var city string
	fmt.Print("Enter the name of the city: ")
	fmt.Scanln(&city)

	// Construct the API request URL
	url := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric", city, apiKey)

	// Send the HTTP request
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal("Error: Unable to connect to OpenWeather API. Please check your internet connection.")
	}
	defer resp.Body.Close()

	// Check if the API response is successful
	if resp.StatusCode != 200 {
		log.Fatalf("Please check the city name and try again.")
	}

	// Decode the JSON response into our struct
	var weatherData WeatherResponse
	err = json.NewDecoder(resp.Body).Decode(&weatherData)
	if err != nil {
		log.Fatal("Error: Unable to process the weather data.")
	}

	// Convert sunrise and sunset timestamps to readable time format
	sunriseTime := time.Unix(weatherData.Sys.Sunrise, 0).Format("15:04")
	sunsetTime := time.Unix(weatherData.Sys.Sunset, 0).Format("15:04")

	// Display the formatted weather information
	fmt.Println("\n Weather Information:")
	fmt.Println("---------------------------")
	fmt.Printf(" City: %s\n", weatherData.Name)
	fmt.Printf(" Condition: %s\n", weatherData.Weather[0].Description)
	fmt.Printf(" Temperature: %.2f°C\n", weatherData.Main.Temp)
	fmt.Printf(" Humidity: %d%%\n", weatherData.Main.Humidity)
	fmt.Printf(" Wind Speed: %.2f m/s\n", weatherData.Wind.Speed)
	fmt.Printf(" Sunrise: %s AM\n", sunriseTime)
	fmt.Printf(" Sunset: %s PM\n", sunsetTime)
	fmt.Println("---------------------------")
}

                

copie this code in yourmain.gofile and excute it :

go run main.go

You should see something like this :


Enter the name of the city: london

 Weather Information:
---------------------------
 City: London
 Condition: clear sky
 Temperature: 12.78°C
 Humidity: 60%
 Wind Speed: 9.77 m/s
 Sunrise: 07:33 AM
 Sunset: 20:34 PM
---------------------------
    

Congratulations! 🎉

You’ve successfully built a weather app in Go! 🚀 Along the way, you learned how to interact with an external API, handle JSON responses, manage environment variables securely, and improve data display.

🚀 Thank you for reading these articles! If you find this content valuable and want to support my work, a coffee would be greatly appreciated! ☕😊

đŸ’» I am a freelance web developer, and I personally create and maintain this website. Any support would help me improve and expand it further! 🙌


☕ Buy me a coffee