github.com/MetalBlockchain/metalgo@v1.11.9/utils/rpc/json.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package rpc 5 6 import ( 7 "bytes" 8 "context" 9 "fmt" 10 "net/http" 11 "net/url" 12 13 rpc "github.com/gorilla/rpc/v2/json2" 14 ) 15 16 func SendJSONRequest( 17 ctx context.Context, 18 uri *url.URL, 19 method string, 20 params interface{}, 21 reply interface{}, 22 options ...Option, 23 ) error { 24 requestBodyBytes, err := rpc.EncodeClientRequest(method, params) 25 if err != nil { 26 return fmt.Errorf("failed to encode client params: %w", err) 27 } 28 29 ops := NewOptions(options) 30 uri.RawQuery = ops.queryParams.Encode() 31 32 request, err := http.NewRequestWithContext( 33 ctx, 34 http.MethodPost, 35 uri.String(), 36 bytes.NewBuffer(requestBodyBytes), 37 ) 38 if err != nil { 39 return fmt.Errorf("failed to create request: %w", err) 40 } 41 42 request.Header = ops.headers 43 request.Header.Set("Content-Type", "application/json") 44 45 resp, err := http.DefaultClient.Do(request) 46 if err != nil { 47 return fmt.Errorf("failed to issue request: %w", err) 48 } 49 50 // Return an error for any non successful status code 51 if resp.StatusCode < 200 || resp.StatusCode > 299 { 52 // Drop any error during close to report the original error 53 _ = resp.Body.Close() 54 return fmt.Errorf("received status code: %d", resp.StatusCode) 55 } 56 57 if err := rpc.DecodeClientResponse(resp.Body, reply); err != nil { 58 // Drop any error during close to report the original error 59 _ = resp.Body.Close() 60 return fmt.Errorf("failed to decode client response: %w", err) 61 } 62 return resp.Body.Close() 63 }