aws / aws-lambda-go

Libraries, samples and tools to help Go developers develop AWS Lambda functions.
Apache License 2.0
3.63k stars 553 forks source link

API Gateway Proxy Headers as http.Header #131

Open jackwellsxyz opened 6 years ago

jackwellsxyz commented 6 years ago

Hello! Any chance we could make the events.APIGatewayProxyRequest.Headers type to match http.Header? It would be nice to take advantage of the http.Header helper functions. Basically have to convert map[string]string to map[string][]string.

bmoffatt commented 6 years ago

To maintain backwards compatibility. I don't think that events.APIGatewayProxyRequest.Headers's type can be changed

This might instead be achieved by adding a func (r *APIGatewayProxyRequest) Header() http.Header {}

piotrkubisa commented 6 years ago

I also don't think events.APIGatewayProxyRequest.Headers should be given in http.Header format. Of course here goes compatibility reasons and having concise API, but also transformation from map[string]string to http.Header (exactly: map[string][]string) on first glance look simple but then you notice there is a lot computation involved, and not usually it is needed for everyone.

If you are transforming a event into a http.Request you may like https://github.com/apex/gateway or http://github.com/piotrkubisa/apigo. Also if you need only http.Header map you definitely find something interesting in tj's code or in my fork and adapt it to your use case. Please note: transformations between events.APIGatewayProxyRequest to http.Request are not cheap (btw. most of time is spent on headers transformation).

piotrkubisa commented 6 years ago

One note related to my previous comment: If #136 will be merged then it will easy to cast into http.Header:

headers := http.Header(event.MultiValueHeaders)

Please note: type-casting map to http.Header won't change keys of headers to follow format of the canonical MIME headers (e.g. Accept-Encoding, Content-Type, User-Agent). Example below might illustrate a problem:

m := map[string][]string{
    "foo-Bar": {"World"},
}

h := http.Header(m)
fmt.Println(h.Get("Foo-Bar"))
// Output: "" (empty string)

Personally, I'd stick to folllowing:

headers := make(http.Header)
for key, values := range event.MultiValueHeaders {
    for _, value := range values {
        headers.Add(key, value)
    }
}

@bmoffatt Could you tell me if it is superfluous to check multiValueHeaders (also multiValueQueryStringParameters) are populated (i.e. via len(event.MultiValueHeaders) > 0) and fallback to event.Headers when they aren't? Is it safe to only use multiValueHeaders instead of headers (the same question applies to multi-value query strings instead of single-value query strings)?