Um JSON lint em Golang

Veja o vídeo desse arquivo aqui.

Um JSON lint em Golang

Esse é um pequeno utilitário de linha de comando para validar e formatar JSON que também pode ser usado como pacote, a ideia inicial era criar um parser para validar o JSON mas não foi necessário, o próprio Golang traz todas as informações que precisamos no erro inclusive o offset do erro e dai foi simples mostrar os erros de forma mais completa inclusive indicando com uma seta exatamente onde esta o erro.

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"

    "github.com/crgimenes/goconfig"
    "github.com/gosidekick/jsonlint"
)

func printError(a ...interface{}) {
    _, err := fmt.Fprintf(os.Stderr, "\x1b[91m%v\033[0;00m\n", a...)
    if err != nil {
        fmt.Println(err)
    }
}

func printIndicator(a ...interface{}) {
    _, err := fmt.Fprintf(os.Stderr, "\x1b[96m%v\033[0;00m\n", a...)
    if err != nil {
        fmt.Println(err)
    }
}

func main() {
    type configFlags struct {
        Input  string `json:"i" cfg:"i" cfgDefault:"stdin" cfgHelper:"input from"`
        Output string `json:"o" cfg:"o" cfgDefault:"stdout" cfgHelper:"output to"`
    }

    cfg := configFlags{}
    goconfig.PrefixEnv = "JSON_LINT"
    err := goconfig.Parse(&cfg)
    if err != nil {
        printError(err)
        os.Exit(-1)
    }
    var j []byte

    if cfg.Input == "stdin" {
        j, err = ioutil.ReadAll(os.Stdin)
        if err != nil {
            printError(err)
            os.Exit(-1)
        }
    } else {
        j, err = ioutil.ReadFile(cfg.Input)
        if err != nil {
            printError(err)
            os.Exit(-1)
        }
    }
    var m interface{}
    err = json.Unmarshal(j, &m)
    if err != nil {
        out, offset := jsonlint.ParseJSONError(j, err)
        printError(out)
        if offset > 0 {
            out = jsonlint.GetErrorJSONSource(j, offset)
            printIndicator(out)
        }
        os.Exit(-1)
    }
    j, err = json.MarshalIndent(m, "", "\t")
    if err != nil {
        printError(err)
        os.Exit(-1)
    }
    if cfg.Output == "stdout" {
        fmt.Println(string(j))
        return
    }
    err = ioutil.WriteFile(cfg.Output, j, 0644)
    if err != nil {
        printError(err)
    }
}

Aqui temos o código do nosso utilitário que também serve de exemplo de como utilizar nosso pacote de tratamento de erro, basicamente basta passar o erro da função json.Unmarshal para a função jsonlint.ParseJSONError e o retorno vai ser uma string contendo uma descrição mais detalhada do erro e o offset de onde esse erro ocorreu, você pode passar o JSON que originou o erro e esse offset para a função jsonlint.GetErrorJSONSource e ela vai gerar uma string contendo a parte do código com problemas junto com uma seta apontando para o primeiro caracter que o parser não conseguiu processar.

Esse utilitário assim como muitos outros esta sendo construído no nosso repositório do grupo de estudos de Go.

Nossos encontros ocorrem todas as quintas-feiras ás 22h00, para participar entre no canal de Golang no slack e procure por #brazil

Cesar Gimenes

Última modificação