github.com/supabase/cli@v1.168.1/pkg/fetcher/http.go (about) 1 package fetcher 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "io" 8 "net/http" 9 10 "github.com/go-errors/errors" 11 ) 12 13 type Fetcher struct { 14 server string 15 client *http.Client 16 editors []RequestEditor 17 } 18 19 type FetcherOption func(*Fetcher) 20 21 func NewFetcher(server string, opts ...FetcherOption) *Fetcher { 22 api := &Fetcher{ 23 server: server, 24 client: http.DefaultClient, 25 } 26 for _, apply := range opts { 27 apply(api) 28 } 29 return api 30 } 31 32 func WithHTTPClient(client *http.Client) FetcherOption { 33 return func(s *Fetcher) { 34 s.client = client 35 } 36 } 37 38 func WithBearerToken(token string) FetcherOption { 39 addHeader := func(req *http.Request) { 40 req.Header.Add("Authorization", "Bearer "+token) 41 } 42 return WithRequestEditor(addHeader) 43 } 44 45 func WithUserAgent(agent string) FetcherOption { 46 addHeader := func(req *http.Request) { 47 req.Header.Add("User-Agent", agent) 48 } 49 return WithRequestEditor(addHeader) 50 } 51 52 func WithRequestEditor(fn RequestEditor) FetcherOption { 53 return func(s *Fetcher) { 54 s.editors = append(s.editors, fn) 55 } 56 } 57 58 type RequestEditor func(req *http.Request) 59 60 func (s *Fetcher) Send(ctx context.Context, method, path string, reqBody any, reqEditors ...RequestEditor) (*http.Response, error) { 61 body, ok := reqBody.(io.Reader) 62 if !ok && reqBody != nil { 63 var buf bytes.Buffer 64 enc := json.NewEncoder(&buf) 65 if err := enc.Encode(reqBody); err != nil { 66 return nil, errors.Errorf("failed to encode request body: %w", err) 67 } 68 reqEditors = append(reqEditors, func(req *http.Request) { 69 req.Header.Set("Content-Type", "application/json") 70 }) 71 body = &buf 72 } 73 // Creates request 74 req, err := http.NewRequestWithContext(ctx, method, s.server+path, body) 75 if err != nil { 76 return nil, errors.Errorf("failed to initialise http request: %w", err) 77 } 78 for _, apply := range s.editors { 79 apply(req) 80 } 81 for _, apply := range reqEditors { 82 apply(req) 83 } 84 // Sends request 85 resp, err := s.client.Do(req) 86 if err != nil { 87 return nil, errors.Errorf("failed to execute http request: %w", err) 88 } 89 if resp.StatusCode >= http.StatusBadRequest { 90 defer resp.Body.Close() 91 data, err := io.ReadAll(resp.Body) 92 if err != nil { 93 return nil, errors.Errorf("Error status %d: %w", resp.StatusCode, err) 94 } 95 return nil, errors.Errorf("Error status %d: %s", resp.StatusCode, data) 96 } 97 return resp, nil 98 } 99 100 func ParseJSON[T any](r io.Reader) (*T, error) { 101 var data T 102 dec := json.NewDecoder(r) 103 if err := dec.Decode(&data); err != nil { 104 return nil, errors.Errorf("failed to parse response body: %w", err) 105 } 106 return &data, nil 107 }