diff --git a/src/fierycod/holy_lambda_ring_adapter/core.cljc b/src/fierycod/holy_lambda_ring_adapter/core.cljc index 3f604ec..1b342be 100644 --- a/src/fierycod/holy_lambda_ring_adapter/core.cljc +++ b/src/fierycod/holy_lambda_ring_adapter/core.cljc @@ -33,7 +33,12 @@ [{:keys [event ctx]}] (let [request-ctx (get event :requestContext) http (get request-ctx :http) - headers (get event :headers) + headers (persistent! (reduce (fn [acc [k v]] + (if (keyword? k) + (assoc! acc (.toLowerCase (name k)) v) + (assoc! acc k v))) + (transient {}) + (get event :headers))) base64? (get event :isBase64Encoded)] (when-not request-ctx (throw (ex-info "Incorrect shape of AWS event. The adapter is compatible with following integrations: HttpApi and RestApi on AWS Api Gateway service. If you're testing locally make sure the event shape is valid e.g. use `sam local start-api` instead of `sam local invoke`." {:ctx :hl-ring-adapter}))) @@ -90,12 +95,16 @@ (h/entrypoint [#'HttpApiProxyGateway]) ```" [response] - (let [^impl/RingResponseBody body (:body response) - {:keys [body encoded?]} (impl/to-hl-response-body body)] - {:statusCode (:status response) - :body body - :isBase64Encoded encoded? - :headers (:headers response)})) + (let [^impl/RingResponseBody body (:body response) + {:keys [body encoded?]} (impl/to-hl-response-body body) + [single-value-headers multi-value-headers] ((juxt remove filter) + (comp coll? val) + (:headers response))] + (cond-> {:statusCode (:status response) + :body body + :isBase64Encoded encoded?} + (seq single-value-headers) (assoc :headers (into {} single-value-headers)) + (seq multi-value-headers) (assoc :multiValueHeaders (into {} multi-value-headers))))) (defn ring<->hl-middleware "Middleware that converts Ring Request/Response model to Holy Lambda (AWS Lambda) Request/Response model. diff --git a/test/fierycod/holy_lambda_ring_adapter/core_test.clj b/test/fierycod/holy_lambda_ring_adapter/core_test.clj index c7f2247..fd2e561 100644 --- a/test/fierycod/holy_lambda_ring_adapter/core_test.clj +++ b/test/fierycod/holy_lambda_ring_adapter/core_test.clj @@ -62,6 +62,34 @@ [hl-request] (ring-spec-props (hra/hl-request->ring-request hl-request))) +(t/deftest response-transform + (t/testing "should correctly parse single value headers" + (let [ring-response {:status 200 + :headers {"upgrade-insecure-requests" "1"}}] + (t/is (= {:statusCode 200, + :body nil, + :isBase64Encoded false, + :headers {"upgrade-insecure-requests" "1"}} + (hra/ring-response->hl-response ring-response))))) + (t/testing "should correctly parse multi value headers" + (let [ring-response {:status 200 + :headers {"set-cookie" ["totalOrders=76" "merged-cart=1"]}}] + (t/is (= {:statusCode 200, + :body nil, + :isBase64Encoded false, + :multiValueHeaders {"set-cookie" ["totalOrders=76" "merged-cart=1"]}} + (hra/ring-response->hl-response ring-response))))) + (t/testing "should correctly parse a mix of single and multi value headers" + (let [ring-response {:status 200 + :headers {"upgrade-insecure-requests" "1" + "set-cookie" ["totalOrders=76" "merged-cart=1"]}}] + (t/is (= {:statusCode 200, + :body nil, + :isBase64Encoded false, + :headers {"upgrade-insecure-requests" "1"} + :multiValueHeaders {"set-cookie" ["totalOrders=76" "merged-cart=1"]}} + (hra/ring-response->hl-response ring-response)))))) + (t/deftest http-api-basic-1 (t/testing "should correctly transform request->ring-request #1" (let [hl-request {:event @@ -190,8 +218,7 @@ (handler (request->ring-request-test request1)))) (t/is (= {:statusCode 200, :body "Hello world", - :isBase64Encoded false, - :headers nil} + :isBase64Encoded false} (hra/ring-response->hl-response (handler (request->ring-request-test request2))))) (t/is (= {:statusCode 200, :body "hello world HTTP/1.1", @@ -202,7 +229,15 @@ :body "hello world HTTP/1.1", :isBase64Encoded false, :headers {"something" "something"}} - ((hra/ring<->hl-middleware basic-ring-handler-async) request2 identity identity)))))) + ((hra/ring<->hl-middleware basic-ring-handler-async) request2 identity identity))))) + + (t/testing "Ensure :headers is a map of downcase strings as keys" + (t/is (= {"content-type" "application/json"} + (:headers (request->ring-request-test {:event {:path "/foo" + :isBase64Encoded false + :headers {:Content-Type "application/json"} + :requestContext {:httpMethod "GET"}} + :ctx nil})))))) (t/deftest http-api-json-coerce-1 (t/testing "json coercion should work"