Pular para o conteúdo principal

victorstein.dev

47/100 Dias de Golang - Aplicação para buscar previsão do tempo - Parte 4

Table of Contents

# Aplicação para buscar previsão do tempo - Parte 4

Vamos trabalhar com a formatação dos JSON’s nesse post. Atualmente estamos somente exibindo o retorno da API, vamos formatar e exibir somente os campos que temos interesse.

Vamo primeiro editar o arquivo cidade.go. Devemos criar o formato de resposta do JSON. No nosso caso o JSON é uma lista de várias cidade com Nome, ID e Estado

type Cidade []struct {
	Nome   string `json:"nome"`
	ID     int    `json:"id"`
	Estado string `json:"estado"`
}

Na função requestsCidade temos que definir uma variável do tipo Cidade

var cidades Cidade

E depois de receber a resposta da api devemos fazer o Unmarshal do JSON.

err = json.Unmarshal(body, &cidades)

if err != nil {
	log.Fatalf("Erro ao fazer parse do JSON: %v", err)
}

Depois tratamos a variável cidades como uma estrutura normal do Golang. Nesse caso faremos um for exibindo o Nome, ID e Estado

fmt.Println("\nCidades encontradas:")
for _, c := range cidades {
	fmt.Printf("Nome: %s, ID: %d, Estado: %s\n", c.Nome, c.ID, c.Estado)
}

No arquivo tempo.go temos uma estrutura um pouco mais complexa. Temos uma struct dentro de outra struct. Veja como é a resposta da API:

{
	"cidade":"Curitiba",
	"estado":"PR",
	"atualizado_em":"2025-04-28",
	"clima":[
		{
			"data":"2025-04-29",
			"condicao":"pn",
			"condicao_desc":"Parcialmente Nublado",
			"min":13,
			"max":22,
			"indice_uv":0
		}
	]
}

Para definirmos essa struct, podemos fazer da seguinte forma:

type Info struct {
	Cidade       string  `json:"cidade"`
	Estado       string  `json:"estado"`
	AtualizadoEm string  `json:"atualizado_em"`
	Clima        []Clima `json:"clima"`
}
type Clima struct {
	Data         string `json:"data"`
	Condicao     string `json:"condicao"`
	CondicaoDesc string `json:"condicao_desc"`
	Min          int    `json:"min"`
	Max          int    `json:"max"`
	IndiceUv     int    `json:"indice_uv"`
}

A chave “clima” é definida como um slice do tipo Clima. Depois seguimos os mesmos passos do script de cidade.

var info Info

err = json.Unmarshal(body, &info)

if err != nil {
	log.Fatalf("Erro ao fazer parse do JSON: %v", err)
}

fmt.Printf("\nPrevisão do tempo para %s/%s\n", info.Cidade, info.Estado)
fmt.Printf("Atualizado em: %s\n\n", info.AtualizadoEm)

for _, clima := range info.Clima {
	fmt.Printf("Data: %s\n", clima.Data)
	fmt.Printf("Condição: %s\n", clima.CondicaoDesc)
	fmt.Printf("Temperatura: Mín %d°C - Máx %d°C\n", clima.Min, clima.Max)
	fmt.Printf("Índice UV: %d\n\n", clima.IndiceUv)
}

Veja como fica a saída dos dois comando:

go run main.go cidade --cidade Curitiba
Cidades encontradas:
Nome: Curitiba, ID: 227, Estado: PR
Nome: Curitibanos, ID: 1728, Estado: SC
go run main.go tempo -i 227
Previsão do tempo para Curitiba/PR
Atualizado em: 2025-04-28

Data: 2025-04-29
Condição: Parcialmente Nublado
Temperatura: Mín 13°C - Máx 22°C
Índice UV: 0

Uma dica bem legal é o JSON-to-Go uma aplicação você coloca o JSON e ele retorna a struct formatada. Muito prático e fácil de usar.

Saída do terminal da execução do Gin

Código final dos arquivos editados:

/*
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/spf13/cobra"
)

var cidadeID string

type Info struct {
	Cidade       string  `json:"cidade"`
	Estado       string  `json:"estado"`
	AtualizadoEm string  `json:"atualizado_em"`
	Clima        []Clima `json:"clima"`
}
type Clima struct {
	Data         string `json:"data"`
	Condicao     string `json:"condicao"`
	CondicaoDesc string `json:"condicao_desc"`
	Min          int    `json:"min"`
	Max          int    `json:"max"`
	IndiceUv     int    `json:"indice_uv"`
}

// tempoCmd represents the tempo command
var tempoCmd = &cobra.Command{
	Use:   "tempo",
	Short: "A brief description of your command",
	Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
	Run: func(cmd *cobra.Command, args []string) {
		requestTempo(cidadeID)
	},
}

func init() {
	rootCmd.AddCommand(tempoCmd)
	tempoCmd.Flags().StringVarP(&cidadeID, "cidadeID", "i", "1", "ID da cidade")
}

func requestTempo(cidadeID string) {

	var info Info

	url := fmt.Sprintf("https://brasilapi.com.br/api/cptec/v1/clima/previsao/%s", cidadeID)

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		log.Fatalf("Erro ao criar request: %v", err)
	}

	client := &http.Client{}

	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("Erro ao fazer request: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("Erro ao ler resposta: %v", err)
	}

	err = json.Unmarshal(body, &info)

	if err != nil {
		log.Fatalf("Erro ao fazer parse do JSON: %v", err)
	}

	fmt.Printf("\nPrevisão do tempo para %s/%s\n", info.Cidade, info.Estado)
	fmt.Printf("Atualizado em: %s\n\n", info.AtualizadoEm)

	for _, clima := range info.Clima {
		fmt.Printf("Data: %s\n", clima.Data)
		fmt.Printf("Condição: %s\n", clima.CondicaoDesc)
		fmt.Printf("Temperatura: Mín %d°C - Máx %d°C\n", clima.Min, clima.Max)
		fmt.Printf("Índice UV: %d\n\n", clima.IndiceUv)
	}
}
package cmd

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/spf13/cobra"
)

var cidade string

type Cidade []struct {
	Nome   string `json:"nome"`
	ID     int    `json:"id"`
	Estado string `json:"estado"`
}

// cidadeCmd represents the cidade command
var cidadeCmd = &cobra.Command{
	Use:   "cidade",
	Short: "Retorna uma listagem de cidades",
	Long: `Retorna dados das cidades candidatas que possuem a string passada como parâmetro
	exemplo de uso: cidadetempo --cidade Curitiba
	`,
	Run: func(cmd *cobra.Command, args []string) {
		requestCidade(cidade)
	},
}

func init() {
	rootCmd.AddCommand(cidadeCmd)
	cidadeCmd.Flags().StringVarP(&cidade, "cidade", "c", "Curitiba", "Cidade que você quer o ID")

}

func requestCidade(cidade string) {

	var cidades Cidade

	url := fmt.Sprintf("https://brasilapi.com.br/api/cptec/v1/cidade/%s", cidade)

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		log.Fatalf("Erro ao criar request: %v", err)
	}

	client := &http.Client{}

	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("Erro ao fazer request: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("Erro ao ler resposta: %v", err)
	}

	err = json.Unmarshal(body, &cidades)

	if err != nil {
		log.Fatalf("Erro ao fazer parse do JSON: %v", err)
	}

	fmt.Println("\nCidades encontradas:")
	for _, c := range cidades {
		fmt.Printf("Nome: %s, ID: %d, Estado: %s\n", c.Nome, c.ID, c.Estado)
	}
}