github.com/mweagle/Sparta@v1.15.0/aws/apigateway/response.go (about) 1 package apigateway 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 ) 9 10 // Error represents an error to return in response to an 11 // API Gateway request. 12 type Error struct { 13 Code int `json:"code"` 14 Err string `json:"err"` 15 Message string `json:"message"` 16 Context map[string]interface{} `json:"context,omitempty"` 17 } 18 19 // Error returns the JSONified version of this error which will 20 // trigger the appropriate integration mapping. 21 func (apigError *Error) Error() string { 22 bytes, bytesErr := json.Marshal(apigError) 23 if bytesErr != nil { 24 bytes = []byte(http.StatusText(http.StatusInternalServerError)) 25 } 26 return string(bytes) 27 } 28 29 // NewErrorResponse returns a response that satisfies 30 // the regular expression used to determine integration mappings 31 // via the API Gateway. messages is a stringable type. Error interface 32 // instances will be properly typecast. 33 func NewErrorResponse(statusCode int, messages ...interface{}) *Error { 34 35 additionalMessages := make([]string, len(messages)) 36 for eachIndex, eachMessage := range messages { 37 switch typedValue := eachMessage.(type) { 38 case error: 39 additionalMessages[eachIndex] = typedValue.Error() 40 default: 41 additionalMessages[eachIndex] = fmt.Sprintf("%v", typedValue) 42 } 43 } 44 45 err := &Error{ 46 Code: statusCode, 47 Err: http.StatusText(statusCode), 48 Message: strings.Join(additionalMessages, " "), 49 Context: make(map[string]interface{}), 50 } 51 if len(err.Err) <= 0 { 52 err.Code = http.StatusInternalServerError 53 err.Err = http.StatusText(http.StatusInternalServerError) 54 } 55 return err 56 } 57 58 // Response is the type returned by an API Gateway function. Note that a 59 // non 2xx HTTP status code should be returned as a Response 60 // type rather than an Error. Errors should be reserved for Lambda 61 // functions that fail to execute. 62 type Response struct { 63 Code int `json:"code,omitempty"` 64 Body interface{} `json:"body,omitempty"` 65 Headers map[string]string `json:"headers,omitempty"` 66 } 67 68 // canonicalResponse is the type for the canonicalized response with the 69 // headers lowercased to match any API-Gateway case sensitive whitelist 70 // matching 71 type canonicalResponse struct { 72 Code int `json:"code,omitempty"` 73 Body interface{} `json:"body,omitempty"` 74 Headers map[string]string `json:"headers,omitempty"` 75 } 76 77 // MarshalJSON is a custom marshaller to ensure that the marshalled 78 // headers are always lowercase 79 func (resp *Response) MarshalJSON() ([]byte, error) { 80 canonicalResponse := canonicalResponse{ 81 Code: resp.Code, 82 Body: resp.Body, 83 } 84 if len(resp.Headers) != 0 { 85 canonicalResponse.Headers = make(map[string]string) 86 for eachKey, eachValue := range resp.Headers { 87 canonicalResponse.Headers[strings.ToLower(eachKey)] = eachValue 88 } 89 } 90 return json.Marshal(&canonicalResponse) 91 } 92 93 // NewResponse returns an API Gateway response object 94 func NewResponse(code int, body interface{}, headers ...map[string]string) *Response { 95 response := &Response{ 96 Code: code, 97 Body: body, 98 } 99 if len(headers) != 0 { 100 response.Headers = make(map[string]string) 101 for _, eachHeaderMap := range headers { 102 for eachKey, eachValue := range eachHeaderMap { 103 response.Headers[eachKey] = eachValue 104 } 105 } 106 } 107 return response 108 }