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  }