github.com/mavryk-network/mvgo@v1.19.9/internal/compose/fetch.go (about)

     1  // Copyright (c) 2023 Blockwatch Data Inc.
     2  // Author: alex@blockwatch.cc, abdul@blockwatch.cc
     3  
     4  package compose
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"net/http/httputil"
    12  	"strings"
    13  
    14  	"github.com/echa/log"
    15  	"github.com/tidwall/gjson"
    16  )
    17  
    18  func Fetch[T any](ctx Context, url string) (*T, error) {
    19  	cleanUrl, jsonPath, hasPath := strings.Cut(url, "#")
    20  	client := http.DefaultClient
    21  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, cleanUrl, nil)
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  	if ctx.apiKey != "" {
    26  		req.Header.Add("X-Api-Key", ctx.apiKey)
    27  	}
    28  	if ctx.Log.Level() == log.LevelDebug {
    29  		ctx.Log.Debugf("%s %s %s", req.Method, req.URL, req.Proto)
    30  	}
    31  	if ctx.Log.Level() == log.LevelTrace {
    32  		d, _ := httputil.DumpRequest(req, true)
    33  		ctx.Log.Trace(string(d))
    34  	}
    35  	res, err := client.Do(req)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	if ctx.Log.Level() == log.LevelTrace {
    40  		d, _ := httputil.DumpResponse(res, true)
    41  		ctx.Log.Trace(string(d))
    42  	}
    43  	if res.StatusCode != 200 {
    44  		return nil, fmt.Errorf("request failed: %s ", res.Status)
    45  	}
    46  	defer res.Body.Close()
    47  	buf, err := io.ReadAll(res.Body)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	if hasPath {
    52  		res := gjson.GetBytes(buf, jsonPath)
    53  		if !res.Exists() {
    54  			return nil, fmt.Errorf("missing path %q in result from %s", jsonPath, cleanUrl)
    55  		}
    56  		buf = []byte(res.Raw)
    57  	}
    58  	var k T
    59  	if err := json.Unmarshal(buf, &k); err != nil {
    60  		return nil, err
    61  	}
    62  	return &k, nil
    63  }