The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/util/json.go

112 lines
3.8 KiB

package util
import (
"encoding/json"
"github.com/jmespath/go-jmespath"
"github.com/grafana/grafana/pkg/util/errutil"
)
// DynMap defines a dynamic map interface.
type DynMap map[string]any
var (
// ErrEmptyJSON is an error for empty attribute in JSON.
ErrEmptyJSON = errutil.NewBase(errutil.StatusBadRequest,
"json-missing-body", errutil.WithPublicMessage("Empty JSON provided"))
// ErrNoAttributePathSpecified is an error for no attribute path specified.
ErrNoAttributePathSpecified = errutil.NewBase(errutil.StatusBadRequest,
"json-no-attribute-path-specified", errutil.WithPublicMessage("No attribute path specified"))
// ErrFailedToUnmarshalJSON is an error for failure in unmarshalling JSON.
ErrFailedToUnmarshalJSON = errutil.NewBase(errutil.StatusBadRequest,
"json-failed-to-unmarshal", errutil.WithPublicMessage("Failed to unmarshal JSON"))
// ErrFailedToSearchJSON is an error for failure in searching JSON.
ErrFailedToSearchJSON = errutil.NewBase(errutil.StatusBadRequest,
"json-failed-to-search", errutil.WithPublicMessage("Failed to search JSON with provided path"))
)
// SearchJSONForStringSliceAttr searches for a slice attribute in a JSON object and returns a string slice.
// The attributePath parameter is a string that specifies the path to the attribute.
// The data parameter is the JSON object that we're searching. It can be a byte slice or a go type.
func SearchJSONForStringSliceAttr(attributePath string, data any) ([]string, error) {
val, err := searchJSONForAttr(attributePath, data)
if err != nil {
return []string{}, err
}
ifArr, ok := val.([]any)
if !ok {
return []string{}, nil
}
result := []string{}
for _, v := range ifArr {
if strVal, ok := v.(string); ok {
result = append(result, strVal)
}
}
return result, nil
}
// SearchJSONForStringAttr searches for a specific attribute in a JSON object and returns a string.
// The attributePath parameter is a string that specifies the path to the attribute.
// The data parameter is the JSON object that we're searching. It can be a byte slice or a go type.
func SearchJSONForStringAttr(attributePath string, data any) (string, error) {
val, err := searchJSONForAttr(attributePath, data)
if err != nil {
return "", err
}
strVal, ok := val.(string)
if ok {
return strVal, nil
}
return "", nil
}
// searchJSONForAttr searches for a specific attribute in a JSON object.
// The attributePath parameter is a string that specifies the path to the attribute.
// The data parameter is the JSON object that we're searching.
// The function returns the value of the attribute and an error if one occurred.
func searchJSONForAttr(attributePath string, data any) (any, error) {
// If no attribute path is specified, return an error
if attributePath == "" {
return "", ErrNoAttributePathSpecified.Errorf("attribute path: %q", attributePath)
}
// If the data is nil, return an error
if data == nil {
return "", ErrEmptyJSON.Errorf("empty json, attribute path: %q", attributePath)
}
// Copy the data to a new variable
var jsonData = data
// If the data is a byte slice, try to unmarshal it into a JSON object
if dataBytes, ok := data.([]byte); ok {
// If the byte slice is empty, return an error
if len(dataBytes) == 0 {
return "", ErrEmptyJSON.Errorf("empty json, attribute path: %q", attributePath)
}
// Try to unmarshal the byte slice
if err := json.Unmarshal(dataBytes, &jsonData); err != nil {
return "", ErrFailedToUnmarshalJSON.Errorf("%v: %w", "failed to unmarshal user info JSON response", err)
}
}
// Search for the attribute in the JSON object
value, err := jmespath.Search(attributePath, jsonData)
if err != nil {
return "", ErrFailedToSearchJSON.Errorf("failed to search user info JSON response with provided path: %q: %w", attributePath, err)
}
// Return the value and nil error
return value, nil
}