github.com/tonto/cli@v0.0.0-20180104210444-aec958fa47db/client/call_fn.go (about) 1 package client 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "os" 9 "strings" 10 ) 11 12 const FN_CALL_ID = "Fn_call_id" 13 14 func EnvAsHeader(req *http.Request, selectedEnv []string) { 15 detectedEnv := os.Environ() 16 if len(selectedEnv) > 0 { 17 detectedEnv = selectedEnv 18 } 19 20 for _, e := range detectedEnv { 21 kv := strings.Split(e, "=") 22 name := kv[0] 23 req.Header.Set(name, os.Getenv(name)) 24 } 25 } 26 27 type apiErr struct { 28 Message string `json:"message"` 29 } 30 31 type callID struct { 32 CallID string `json:"call_id"` 33 Error apiErr `json:"error"` 34 } 35 36 func CallFN(u string, content io.Reader, output io.Writer, method string, env []string, includeCallID bool) error { 37 if method == "" { 38 if content == nil { 39 method = "GET" 40 } else { 41 method = "POST" 42 } 43 } 44 45 req, err := http.NewRequest(method, u, content) 46 if err != nil { 47 return fmt.Errorf("error running route: %s", err) 48 } 49 50 req.Header.Set("Content-Type", "application/json") 51 52 if len(env) > 0 { 53 EnvAsHeader(req, env) 54 } 55 56 resp, err := http.DefaultClient.Do(req) 57 if err != nil { 58 return fmt.Errorf("error running route: %s", err) 59 } 60 // for sync calls 61 if call_id, found := resp.Header[FN_CALL_ID]; found { 62 if includeCallID { 63 fmt.Fprint(os.Stderr, fmt.Sprintf("Call ID: %v\n", call_id[0])) 64 } 65 io.Copy(output, resp.Body) 66 } else { 67 // for async calls and error discovering 68 c := &callID{} 69 err = json.NewDecoder(resp.Body).Decode(c) 70 if err == nil { 71 // decode would not fail in both cases: 72 // - call id in body 73 // - error in body 74 // that's why we need to check values of attributes 75 if c.CallID != "" { 76 fmt.Fprint(os.Stderr, fmt.Sprintf("Call ID: %v\n", c.CallID)) 77 } else { 78 fmt.Fprint(output, fmt.Sprintf("Error: %v\n", c.Error.Message)) 79 } 80 } else { 81 return err 82 } 83 } 84 85 if resp.StatusCode >= 400 { 86 // TODO: parse out error message 87 return fmt.Errorf("error calling function: status %v", resp.StatusCode) 88 } 89 90 return nil 91 }