Na web, o JSON é conhecido como um dos principais formatos de reapresentação de dados, e sua fama se dá ao fato de ele ser leve (compare com o formato XML pra ver), simples e compacto, facilitando o parsing das informações pela aplicação.
A verdade é que já existem muitas formas de ler um arquivo JSON usando o golang, mas hoje vamos restringir o nosso estudo a um parsing usando apenas o pacotes da biblioteca padrão da linguagem (o GO tem milhares de pacotes ‘nativos’, por assim dizer, que facilitam nossa vida mantendo o programa leve).
Vamos lá!
Pré-requisitos: vamos partir do pressuposto de que você já esteja ciente da instalação do GO em sua máquina, beleza? Caso não tenha instalado ainda, dê uma olhada nesses artigos bacanas:
Ou ainda na documentação oficial que – pasmem – está em português, e faça a instalação antes de começarmos.
Passo 1 – Ferramentas
Para esse artigo vamos usar as seguintes ferramentas:
- GO Versão 1.12+ (na minha máquina é essa, mas você pode utilizar a versão mais atual também)
- Visual Code
- Packages GO: digitar a instrução go get para baixar os pacotes
Passo 2 – Estrutura de um programa em GO
Os programas em GO devem ser criados dentro da pasta source, definida na instalação, que por padrão é “C:\Users\nome-do-seu-usuario\go\src”. Dentro dessa pasta vamos criar uma pasta chamada go-read-json-file.
Todo programa em go precisa de um arquivo inicial, conhecido como main, que vai ser executado ao inicializarmos a aplicação.
Aqui vamos exemplificar com esse arquivo, mas todo arquivo em go tem basicamente a mesma estrutura, que é essa abaixo:
Estrutura dos arquivos em Go
package main //nome do package. Como estamos na raiz do programa o nome da package será "main"
import (
//Declaração de todos os pacotes que serão utilizados nesse arquivo
)
func main() {
//Instruções iniciais da aplicação.
}
Pois bem, vamos entrar dentro dessa pasta a partir do Visual Studio Code e criar um novo arquivo chamado main.go, onde vai ficar todo nosso código.
Passo 3 – Conhecendo a estrutura do JSON
Vamos trabalhar com um objeto bem simples (por enquanto, muHAhaAHhah), que vai conter algumas propriedades de um objeto livro, conforme apresentado no trecho abaixo:
{
"name":"Programando em Go: Crie aplicações com a linguagem do Google",
"publisher":"Casa do código",
"author": "Caio Filipini",
"link":"https://www.casadocodigo.com.br/products/livro-google-go"
}
Passo 4 – Criando o objeto em GO
Para converter essa estrutura JSON para uma struct – é assim que chamamos classes em GO – podemos usar a ferramenta JSON-to-Go.
Basta colar o json lá que ela converte para o formato de classe do GO rapidinho, precisando apenas ajustar seu nome ou quebrar em mais structs, se necessário.
Book: nossa primeira struct
type Book struct {
Name string `json:"name"`
Publisher string `json:"publisher"`
Author string `json:"author"`
Link string `json:"link"`
}
Passo 5 – Abrindo o arquivo JSON
Pacotes
Aqui vamos usar a função Open do pacote nativo os. Para utilizarmos os pacotes no Golang basta importarmos o pacote através da instrução abaixo:
Exemplos de imports em golang
import (
"nome_do_pacote" //pacote nativo
"https://github.com/user/nome_do_pacote" //pacote da comunidade - endereço completo do pacote
)
Aqui nessa POC vamos trabalhar apenas com pacotes nativos, conforme a imagem abaixo:
Import dos pacotes nativos que vamos usar
import (
"fmt"
"io/ioutil"
"os"
"encoding/json"
)
No trecho abaixo estamos abrindo nosso arquivo JSON através da função os.Open, que além de retornar o arquivo jsonFile, retorna um objeto do tipo error, para que seja possível verificar se houve algum erro na abertura do arquivo:
jsonFile, err := os.Open(`book.json`)
Error
É sempre importante verificar se ocorreram erros durante a execução do nosso programa. Aqui vamos fazer uma verificação simples, apenas apresentando o erro na tela, caso ocorra o erro. Conforme a instrução a seguir:
if err != nil {
//Caso tenha tido erro, ele é apresentado na tela
fmt.Println(err)
}
Esse trecho será usado sempre que as funções retornarem erros para podermos realizar alguma tratativa em relação a eles.
Dispose e Defer
Uma boa prática é sempre fechar, ou dar dispose, nos objetos que utilizamos, para não ocuparmos memória, tão pouco recursos de I/O, desnecessários durante a execução do programa.
Algumas linguagens possuem um funcionalidade chamada em geral de “Garbage Collector”, que é um tipo de lixeiro que passa de vez em quando para limpar a memória. O GO também possui esse recurso para gerenciar a memória.
Contudo, não existe essa funcionalidade para a gestão de recursos de I/O, como conexão de rede, conexão de banco de dados ou arquivos físicos. Para fazer isso temos um instrução que auxilia nessa finalidade: o defer. Essa instrução é executada no fim de cada função com o bloco de código que inserirmos. Com o código abaixo fechamos o arquivo “jsonFile” ao fim da função.
defer jsonFile.Close()
Passo 6 – Decodificando o JSON para nosso objeto
Para conseguir manipular o nosso json dentro de um objeto Book, vamos precisar transformar nosso arquivo primeiro em um array de bytes para depois utilizar a função json.Unmarshal para transformar os bytes em um objeto Book. No código é exatamente o que estamos fazendo.
//Aqui o arquivo é convertido para uma variável array de bytes, através do pacote "io/ioutil"
byteValueJSON, _:= ioutil.ReadAll(jsonFile)
//Declaração abreviada de um objeto do tipo Book
objBook := Book{}
//Conversão da variável byte em um objeto do tipo struct Book
json.Unmarshal(byteValueJSON, &objBook)
Passo 7 – Alterando o objeto Book
A alteração de uma propriedade em GO é super simples e parecida com muitas linguagens. Basta usar a instrução “nome_do_objeto.nome_da_propriedade”. Segue um exemplo para alterarmos e vermos a alteração da propriedade no console:
Antes e depois da propriedade Name do objeto objBook
//Apresentação na tela do campo Name
fmt.Println(objBook.Name)
//Alteração do campo Name
objBook.Name = "New book name"
//Apresentação no console do novo valor do campo Name
fmt.Println(objBook.Name)
Vamos executar o programa agora pra ver essa alteração no console. Para isso, digite a seguinte alteração no console: go run main.go
.
Passo 8 – Salvando em um arquivo JSON
Agora, para finalizar com chave de ouro, vamos salvar nossa struct alterada em um novo arquivo? Vamos!
Para isso basta converter o objeto objBook para um array de bytes usando a função json.Marshal, e depois, através da função ioutil.WriteFile, salvar em um novo arquivo.
//Aqui vamos converter nosso objBook com o nome alterado em bytes
byteValueJSON, err = json.Marshal(objBook)
if err != nil {
fmt.Println(err)
}
//Por fim vamos salvar em um arquivo JSON alterado.
err = ioutil.WriteFile("newBook.json", byteValueJSON, 0644)
if err != nil {
fmt.Println(err)
}
Usei o nome newBook.json para não sobrescrever o arquivo original. Sempre que executar sua aplicação, o arquivo newBook.json será sobrescrito.
Extras
Se quiser se aprofundar nos packages de manipulação de json, dê uma olhada nesses links:
- How to access deeply nested JSON data using Go (lang)?
- JSON Schema And Go
- Query JSON data using Golang (gojsonq)
E fim! Sua primeira aplicação em GO está finalizada! Caso queira consultar o código, subi um repo no GIT com a solução (com o comentário de cada linha de código).
Espero que tenha ajudado, e se tiver alguma dúvida ou sugestão, deixe nos comentários.
Até mais!