Search code examples
jsongojsonnet

Using go-jsonnet to return pure JSON


I am using Google's go-jsonnet library to evaluate some jsonnet files.

I have a function, like so, which renders a Jsonnet document:

// Takes a list of jsonnet files and imports each one and mixes them with "+"
func renderJsonnet(files []string, param string, prune bool) string {

  // empty slice
  jsonnetPaths := files[:0]

  // range through the files
  for _, s := range files {
    jsonnetPaths = append(jsonnetPaths, fmt.Sprintf("(import '%s')", s))
  }

  // Create a JSonnet VM
  vm := jsonnet.MakeVM()

  // Join the slices into a jsonnet compat string
  jsonnetImport := strings.Join(jsonnetPaths, "+")

  if param != "" {
    jsonnetImport = "(" + jsonnetImport + ")" + param
  }

  if prune {
    // wrap in std.prune, to remove nulls, empty arrays and hashes
    jsonnetImport = "std.prune(" + jsonnetImport + ")"
  }

  // render the jsonnet
  out, err := vm.EvaluateSnippet("file", jsonnetImport)

  if err != nil {
    log.Panic("Error evaluating jsonnet snippet: ", err)
  }

  return out

}

This function currently returns a string, because the jsonnet EvaluateSnippet function returns a string.

What I now want to do is render that result JSON using the go-prettyjson library. However, because the JSON i'm piping in is a string, it's not rendering correctly.

So, some questions:

  • Can I convert the returned JSON string to a JSON type, without knowing beforehand what struct to marshal it into
  • if not, can I render the json in a pretty manner some other way?
  • Is there an option, function or method I'm missing here to make this easier?

Solution

  • Can I convert the returned JSON string to a JSON type, without knowing beforehand what struct to marshal it into

    Yes. It's very easy:

    var jsonOut interface{}
    err := json.Unmarshal([]byte(out), &jsonOut)
    if err != nil {
        log.Panic("Invalid json returned by jsonnet: ", err)
    }
    formatted, err := prettyjson.Marshal([]byte(jsonOut))
    if err != nil {
        log.Panic("Failed to format jsonnet output: ", err)
    }
    

    More info here: https://blog.golang.org/json-and-go#TOC_5.

    Is there an option, function or method I'm missing here to make this easier?

    Yes. The go-prettyjson library has a Format function which does the unmarshalling for you:

    formatted, err := prettyjson.Format([]byte(out))
    if err != nil {
        log.Panic("Failed to format jsonnet output: ", err)
    }
    

    can I render the json in a pretty manner some other way?

    Depends on your definition of pretty. Jsonnet normally outputs every field of an object and every array element on a separate line. This is usually considered pretty printing (as opposed to putting everything on the same line with minimal whitespace to save a few bytes). I suppose this is not good enough for you. You can write your own manifester in jsonnet which formats it to your liking (see std.manifestJson as an example).