Команда Go for Devs подготовила перевод пошагового руководства: как написать собственное CLI-приложение прогноза погоды на Go. Проект охватывает всё — от HTTP-запросов и парсинга JSON до удобного интерфейса командной строки. Отличная практика для новичков и хороший повод освежить базовые навыки тем, кто уже работает с Go.
Сегодня мы займёмся увлекательным проектом — напишем CLI-приложение прогноза погоды на Go. В этой статье я проведу вас через все шаги создания собственного консольного приложения для получения погоды. Независимо от того, только ли вы начинаете изучать Go или ищете интересный проект для практики — этот туториал вам подойдёт.
Мы разберём всё: от настройки проекта и написания кода до тестирования приложения. И обещаю — каждую строчку кода я объясню так, чтобы вы точно понимали, что происходит «под капотом».
Так что берите любимый напиток, открывайте редактор — и поехали писать код!
Настройка проекта
Прежде чем приступить к написанию кода, давайте определимся с целью. Мы хотим создать CLI-приложение на Go, которое будет получать данные о погоде с онлайн-API и показывать их в терминале. В качестве источника данных используем OpenWeatherMap. Если у вас ещё нет API-ключа, обязательно зарегистрируйтесь и получите бесплатный ключ.
Наше приложение будет выполнять следующие шаги:
Принимать на вход название города.
Обращаться к API прогноза погоды.
Разбирать JSON-ответ.
Отображать текущую информацию о погоде.
Этот проект прост, но при этом полезен. Следуя инструкциям, вы получите практический опыт работы с HTTP-запросами, парсингом JSON и созданием консольных интерфейсов в Go.
Понимание работы CLI-приложения прогноза погоды
Прежде чем переходить к коду, разберёмся, что именно будет делать наше CLI-приложение на Go:
Ввод пользователя. Приложение будет запрашивать у пользователя название города или принимать его как аргумент командной строки.
HTTP-запрос. С помощью встроенного пакета Go
net/http
мы отправим HTTP GET-запрос к API OpenWeatherMap.Парсинг JSON. После получения ответа мы преобразуем JSON-данные в структуры Go.
Отображение данных. В конце красиво выведем детали прогноза погоды (температуру, влажность и описание) в терминал.
Шаг 1: Создание проекта и инициализация модулей
Для начала создадим папку проекта и инициализируем модуль Go.
Создайте новую директорию для проекта:
mkdir weather-cli-app
cd weather-cli-app
Инициализируйте модуль Go:
go mod init weather-cli-app
Эта команда создаст файл go.mod
, в котором будут отслеживаться зависимости проекта. Теперь у нас есть чистая основа для создания CLI-приложения прогноза погоды на Go.
Шаг 2: Настройка API-клиента
Теперь, когда проект готов, нужно создать API-клиент для получения данных о погоде. Мы напишем простую функцию, которая будет отправлять HTTP GET-запрос к OpenWeatherMap.
Создайте новый файл weather.go
:
touch weather.go
Добавьте следующий код в weather.go
:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
)
// WeatherData — структура под JSON-ответ OpenWeatherMap.
type WeatherData struct {
Name string `json:"name"`
Main struct {
Temp float64 `json:"temp"`
Humidity int `json:"humidity"`
} `json:"main"`
Weather []struct {
Description string `json:"description"`
} `json:"weather"`
}
// getWeatherData получает данные о погоде для указанного города.
func getWeatherData(city string, apiKey string) (*WeatherData, error) {
// Формируем URL API. Используем метрическую систему (градусы Цельсия).
url := fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric", city, apiKey)
// Отправляем HTTP-запрос.
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to make request: %v", err)
}
defer resp.Body.Close()
// Проверяем, что запрос прошёл успешно.
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := ioutil.ReadAll(resp.Body)
return nil, fmt.Errorf("error: received status code %d: %s", resp.StatusCode, string(bodyBytes))
}
// Читаем тело ответа.
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %v", err)
}
// Декодируем JSON в структуру WeatherData.
var weather WeatherData
err = json.Unmarshal(bodyBytes, &weather)
if err != nil {
return nil, fmt.Errorf("failed to decode JSON: %v", err)
}
return &weather, nil
}
Пояснение к коду:
Мы объявляем структуру
WeatherData
, которая соответствует JSON-ответу OpenWeatherMap. Это позволяет удобно декодировать данные из API.Функция принимает название города и API-ключ: она собирает URL запроса, отправляет HTTP GET и обрабатывает ответ. В случае успеха JSON разбирается в структуру
WeatherData
.
Следуя этим шагам, вы получили рабочий компонент API-клиента для вашего CLI-приложения погоды на Go.
Шаг 3: Создаём интерфейс командной строки
Теперь настроим интерфейс командной строки. Пользователь сможет передать название города прямо при запуске приложения. Если этого не сделать, программа запросит ввод интерактивно.
Создайте файл main.go
:
touch main.go
Добавьте следующий код в main.go
:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
// Читаем API-ключ из переменной окружения.
apiKey := os.Getenv("OPENWEATHER_API_KEY")
if apiKey == "" {
fmt.Println("Error: Please set the OPENWEATHER_API_KEY environment variable.")
os.Exit(1)
}
// Проверяем, передано ли название города в аргументах командной строки.
var city string
if len(os.Args) > 1 {
city = strings.Join(os.Args[1:], " ")
} else {
// Запрашиваем у пользователя название города, если аргумент не указан.
fmt.Print("Enter the city name: ")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Error reading input:", err)
return
}
city = strings.TrimSpace(input)
}
// Получаем данные о погоде.
weather, err := getWeatherData(city, apiKey)
if err != nil {
fmt.Println("Error fetching weather data:", err)
return
}
// Отображаем данные о погоде.
displayWeatherData(weather)
}
Пояснение к коду:
API-ключ считывается из переменной окружения
OPENWEATHER_API_KEY
. Такой способ позволяет безопасно хранить чувствительные данные.Программа проверяет, указал ли пользователь название города в аргументах командной строки. Если нет, она предложит ввести его вручную.
После получения названия города вызывается функция
getWeatherData
, а затем данные передаются для отображения.
Этот фрагмент объединяет воедино интерфейс командной строки нашего CLI-приложения прогноза погоды на Go.
Шаг 4: Парсим и отображаем данные о погоде
Теперь нам нужна функция, которая красиво отформатирует и выведет данные о погоде. Она будет принимать данные, полученные от API, и печатать их в терминале.
В том же файле main.go
добавьте следующую функцию:
// displayWeatherData выводит информацию о погоде в удобном для пользователя формате.
func displayWeatherData(weather *WeatherData) {
fmt.Printf("\nWeather for %s:\n", weather.Name)
if len(weather.Weather) > 0 {
fmt.Printf("Description: %s\n", strings.Title(weather.Weather[0].Description))
}
fmt.Printf("Temperature: %.2f°C\n", weather.Main.Temp)
fmt.Printf("Humidity: %d%%\n\n", weather.Main.Humidity)
}
Пояснение к коду:
Функция выводит название города, описание погоды, температуру и влажность. Для аккуратного форматирования используется
fmt.Printf
.С помощью
strings.Title
описание погоды приводится к красивому виду с заглавной буквы.
Эта функция завершает наш проект CLI-приложения прогноза погоды на Go — теперь пользователь получает понятную и полезную информацию о погоде прямо в терминале.
Шаг 5: Тестирование и запуск приложения
Перед тем как завершить работу, давайте протестируем приложение. Вот как запустить ваше CLI-приложение погоды на Go:
Установите API-ключ в переменную окружения:
Для Linux/Mac:
export OPENWEATHER_API_KEY=your_api_key_here
Для Windows (Command Prompt):
set OPENWEATHER_API_KEY=your_api_key_here
Запустите приложение, передав название города:
go run main.go London
Если вы не передадите название города, приложение предложит ввести его вручную.
Вы должны увидеть что-то вроде этого:
Weather for London:
Description: Clear Sky
Temperature: 15.00°C
Humidity: 67%
Поздравляем! Вы успешно создали CLI-приложение погоды на Go. Теперь ваша программа умеет получать и отображать актуальную информацию о погоде по запросу пользователя.
Полный исходный код
Для удобства ниже приведён полный исходный код CLI-приложения погоды на Go:
Weather App
// main.go
package main
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
)
// WeatherData — структура под JSON-ответ OpenWeatherMap.
type WeatherData struct {
Name string `json:"name"`
Main struct {
Temp float64 `json:"temp"`
Humidity int `json:"humidity"`
} `json:"main"`
Weather []struct {
Description string `json:"description"`
} `json:"weather"`
}
// getWeatherData получает данные о погоде для указанного города.
func getWeatherData(city string, apiKey string) (*WeatherData, error) {
// Формируем URL API. Используем метрическую систему (градусы Цельсия).
url := fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric", city, apiKey)
// Отправляем HTTP-запрос.
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to make request: %v", err)
}
defer resp.Body.Close()
// Проверяем, что запрос прошёл успешно.
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := ioutil.ReadAll(resp.Body)
return nil, fmt.Errorf("error: received status code %d: %s", resp.StatusCode, string(bodyBytes))
}
// Читаем тело ответа.
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %v", err)
}
// Декодируем JSON в структуру WeatherData.
var weather WeatherData
err = json.Unmarshal(bodyBytes, &weather)
if err != nil {
return nil, fmt.Errorf("failed to decode JSON: %v", err)
}
return &weather, nil
}
// displayWeatherData выводит информацию о погоде в удобном для пользователя формате.
func displayWeatherData(weather *WeatherData) {
fmt.Printf("\nWeather for %s:\n", weather.Name)
if len(weather.Weather) > 0 {
fmt.Printf("Description: %s\n", strings.Title(weather.Weather[0].Description))
}
fmt.Printf("Temperature: %.2f°C\n", weather.Main.Temp)
fmt.Printf("Humidity: %d%%\n\n", weather.Main.Humidity)
}
func main() {
// Читаем API-ключ из переменной окружения.
apiKey := os.Getenv("OPENWEATHER_API_KEY")
if apiKey == "" {
fmt.Println("Error: Please set the OPENWEATHER_API_KEY environment variable.")
os.Exit(1)
}
// Проверяем, передано ли название города в аргументах командной строки.
var city string
if len(os.Args) > 1 {
city = strings.Join(os.Args[1:], " ")
} else {
// Запрашиваем у пользователя название города, если аргумент не указан.
fmt.Print("Enter the city name: ")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Error reading input:", err)
return
}
city = strings.TrimSpace(input)
}
// Получаем данные о погоде.
weather, err := getWeatherData(city, apiKey)
if err != nil {
fmt.Println("Error fetching weather data:", err)
return
}
// Отображаем данные о погоде.
displayWeatherData(weather)
}
Русскоязычное Go сообщество

Друзья! Эту статью перевела команда «Go for Devs» — сообщества, где мы делимся практическими кейсами, инструментами для разработчиков и свежими новостями из мира Go. Подписывайтесь, чтобы быть в курсе и ничего не упустить!
Итоги
Создание CLI-приложения погоды на Go — это не только интересно, но и отличный способ прокачать навыки программирования. Вы научились настраивать проект, отправлять HTTP-запросы, парсить JSON и делать удобный инструмент для командной строки. Продолжая работу с Go, подумайте о расширении проекта, например:
Кэширование данных о погоде для быстрого доступа.
Поддержка нескольких городов в одном запросе.
Улучшенная обработка ошибок и логирование.
Надеюсь, вам понравился этот туториал. Дальше — экспериментируйте, дорабатывайте и, возможно, поделитесь своей версией CLI-приложения погоды с коллегами.
Удачного кодинга и пусть погода всегда радует!)