Skip to content

Emit JSON for scripting

A CLI that is scriptable needs a stable, machine-readable envelope alongside its human output. output provides the Response envelope and Emit.

The envelope

type Response struct {
    Status  string `json:"status"`            // "success" | "error" | "warning"
    Command string `json:"command"`
    Data    any    `json:"data,omitempty"`
    Error   string `json:"error,omitempty"`
}

Emit — only when the format is JSON

Emit writes the envelope only when the renderer's format is json; in any other format it is a no-op. That lets you write both paths unconditionally:

r := output.New(output.WithWriter(os.Stdout), output.WithFormat(format))

result, err := doWork()
if err != nil {
    // In JSON mode this prints an error envelope; in text mode it is a no-op,
    // so return the error and let your normal text error-handling run.
    _ = r.EmitError("update", err)
    return err
}

if r.IsJSON() {
    return r.Emit(output.Response{
        Status:  output.StatusSuccess,
        Command: "update",
        Data:    result,
    })
}

// Human-readable path:
fmt.Fprintf(os.Stdout, "Updated to %s\n", result.Version)
return nil

Output for --output json:

{
  "status": "success",
  "command": "update",
  "data": { "version": "1.4.0" }
}

From a cobra command

If you build on cobra, the output/cobra subpackage reads the --output flag and the command's writer for you — see Wire it to a cobra CLI:

import ocobra "gitlab.com/phpboyscout/go/output/cobra"

return ocobra.NewRenderer(cmd).Emit(output.Response{
    Status: output.StatusSuccess, Command: "update", Data: result,
})