├── .gitignore ├── Readme.md ├── aws └── shim.go ├── eawsy └── shim.go ├── examples └── helloWorld │ ├── Readme.md │ ├── aws │ ├── Makefile │ └── handler.go │ ├── eawsy │ ├── Makefile │ └── handler.go │ ├── hello │ └── hello.go │ ├── main.go │ └── swagger.json ├── go.mod ├── go.sum └── utils └── adapters.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Go template 3 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 4 | *.o 5 | *.a 6 | *.so 7 | 8 | # Folders 9 | _obj 10 | _test 11 | 12 | # Architecture specific extensions/prefixes 13 | *.[568vq] 14 | [568vq].out 15 | 16 | *.cgo1.go 17 | *.cgo2.c 18 | _cgo_defun.c 19 | _cgo_gotypes.go 20 | _cgo_export.* 21 | 22 | _testmain.go 23 | 24 | *.exe 25 | *.test 26 | *.prof 27 | 28 | *.zip 29 | .idea 30 | 31 | examples/helloWorld/helloWorld 32 | examples/helloWorld/aws/handler 33 | 34 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # AWS API Gateway to Lambda Shim using [http.Handler](https://golang.org/pkg/net/http/#Handler) 2 | 3 | This software is based, in part, on the work done by [eawsy](http://github.com/eawsy/aws-lambda-go/) 4 | Their terrific idea was to use the Python 2.7 runtime available in [AWS Lambda](https://aws.amazon.com/lambda/) 5 | to run [go](http://golang.com) programs. I was in the midst of creating a new API using [goa](http://goa.design) 6 | and it dawned on me that if I could somehow trick goa into responding to 7 | [AWS Api Gateway](https://aws.amazon.com/api-gateway/) requests, I could have a service that could both run standalone 8 | and serverless on AWS's API Gateway and Lambda. 9 | 10 | So I created this. 11 | 12 | Now that AWS Lambda supports GO programs natively there is no reason to use 13 | eawsy but I have maintained support for it. I have updated the usage instructions 14 | to include examples for both AWS Native and eAWSy. 15 | 16 | ## Usage 17 | 18 | ### AWS Native 19 | 20 | 21 | For complete details checkout the [helloWorld example](examples/helloWorld/aws) 22 | 23 | The basic steps for usage are as follows: 24 | 25 | **NOTE:** you need to replace the '*${AWS_ACCOUNT_ID}*' place holder in 26 | the swagger.json and the aws commands above with your account id. 27 | 28 | 1. separate your configuration of your web service muxer from your call to http.ListenAndServe. 29 | 30 | ```go 31 | package hello 32 | 33 | import ( 34 | "net/http" 35 | ... 36 | ) 37 | 38 | func InitHandler() (http.Handler, error) { 39 | mux := http.NewServeMux() 40 | mux.HandleFunc("/hello/", func(w http.ResponseWriter, req *http.Request) { 41 | ... 42 | }) 43 | return mux, nil 44 | } 45 | ``` 46 | 2. Create your main() for your web service: 47 | 48 | ```go 49 | package main 50 | 51 | import ( 52 | "github.com/danapsimer/aws-lambda-shim/examples/helloWorld/hello" 53 | "log" 54 | "net/http" 55 | ) 56 | 57 | func main() { 58 | handler, _ := hello.InitHandler() 59 | log.Fatal(http.ListenAndServe(":8080", handler)) 60 | } 61 | ``` 62 | 3. create your main() for your aws: 63 | ```go 64 | package main 65 | import ( 66 | "github.com/danapsimer/aws-lambda-shim/examples/helloWorld/hello" 67 | "github.com/danapsimer/aws-lambda-shim/aws" 68 | ) 69 | func init() { 70 | shim.NewHttpHandlerShim(hello.InitHandler) 71 | } 72 | func main() { 73 | } 74 | ``` 75 | 3. Make your executable: 76 | 77 | ```Makefile 78 | build: 79 | GOOS=linux go build -o handler 80 | 81 | pack: 82 | zip handler.zip handler 83 | ``` 84 | 4. Create your lambda function in AWS: (in the directory your handler was built) 85 | 86 | ```bash 87 | aws lambda create-function \ 88 | --function-name hello-world-api \ 89 | --runtime go1.x --handler handler --zip-file fileb://handler.zip \ 90 | --role arn:aws:iam::${AWS_ACCOUNT_ID}:role/lambda_basic_execution 91 | ``` 92 | 5. Create your API Gateway API: 93 | 94 | ```bash 95 | aws apigateway import-rest-api \ 96 | --body file://examples/helloWorld/swagger.json --region us-east-1 97 | aws lambda add-permission --region us-east-1 \ 98 | --function-name hello-world-api --statement-id 5 \ 99 | --principal apigateway.amazonaws.com --action lambda:InvokeFunction \ 100 | --source-arn 'arn:aws:execute-api:us-east-1:${AWS_ACCOUNT_ID}:3l3za8xwnd/*/*/*' 101 | ``` 102 | 103 | ### Eawsy 104 | 105 | For complete details checkout the [helloWorld example](examples/helloWorld/eawsy) 106 | 107 | The basic steps for usage are as follows: 108 | 109 | **NOTE:** you need to replace the '*${AWS_ACCOUNT_ID}*' place holder in 110 | the swagger.json and the aws commands above with your account id. 111 | 112 | 1. separate your configuration of your web service muxer from your call to http.ListenAndServe. 113 | 114 | ```go 115 | package hello 116 | 117 | import ( 118 | "net/http" 119 | ... 120 | ) 121 | 122 | func InitHandler() (http.Handler, error) { 123 | mux := http.NewServeMux() 124 | mux.HandleFunc("/hello/", func(w http.ResponseWriter, req *http.Request) { 125 | ... 126 | }) 127 | return mux, nil 128 | } 129 | ``` 130 | 2. Create your main() for your web service: 131 | 132 | ```go 133 | package main 134 | 135 | import ( 136 | "github.com/danapsimer/aws-lambda-shim/examples/helloWorld/hello" 137 | "log" 138 | "net/http" 139 | ) 140 | 141 | func main() { 142 | handler, _ := hello.InitHandler() 143 | log.Fatal(http.ListenAndServe(":8080", handler)) 144 | } 145 | ``` 146 | 3. create your main() for your eawsy: 147 | 148 | ```go 149 | package main 150 | 151 | import ( 152 | "github.com/danapsimer/aws-lambda-shim/examples/helloWorld/hello" 153 | "github.com/danapsimer/aws-lambda-shim/eawsy" 154 | ) 155 | 156 | func init() { 157 | shim.NewHttpHandlerShim(hello.InitHandler) 158 | } 159 | 160 | func main() { 161 | } 162 | ``` 163 | 4. Make your eawsy: 164 | 165 | ```Makefile 166 | build: 167 | go build -buildmode=c-shared -ldflags="-w -s" -o handler.so 168 | 169 | pack: 170 | zip handler.zip handler.so 171 | ``` 172 | 5. Create your eawsy in AWS: (in the directory your eawsy handler was built) 173 | 174 | ```bash 175 | aws lambda create-function \ 176 | --function-name hello-world-api \ 177 | --runtime python2.7 --handler handler.handle --zip-file fileb://handler.zip \ 178 | --role arn:aws:iam::${AWS_ACCOUNT_ID}:role/lambda_basic_execution 179 | ``` 180 | 6. Create your API Gateway API: 181 | 182 | ```bash 183 | aws apigateway import-rest-api \ 184 | --body file://examples/helloWorld/swagger.json --region us-east-1 185 | aws lambda add-permission --region us-east-1 \ 186 | --function-name hello-world-api --statement-id 5 \ 187 | --principal apigateway.amazonaws.com --action lambda:InvokeFunction \ 188 | --source-arn 'arn:aws:execute-api:us-east-1:${AWS_ACCOUNT_ID}:3l3za8xwnd/*/*/*' 189 | ``` 190 | 191 | -------------------------------------------------------------------------------- /aws/shim.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "fmt" 7 | "github.com/aws/aws-lambda-go/events" 8 | "github.com/aws/aws-lambda-go/lambda" 9 | "github.com/danapsimer/aws-api-to-lambda-shim/utils" 10 | "io" 11 | "io/ioutil" 12 | "log" 13 | "net/http" 14 | "net/url" 15 | "strings" 16 | ) 17 | 18 | type ShimInitFunc func() (http.Handler, error) 19 | 20 | type HttpHandlerShim struct { 21 | init ShimInitFunc 22 | initCalled bool 23 | handler http.Handler 24 | } 25 | 26 | func NewHttpHandlerShim(init ShimInitFunc) (*HttpHandlerShim, error) { 27 | shim := &HttpHandlerShim{ 28 | init: init, 29 | initCalled: false, 30 | handler: nil, 31 | } 32 | lambda.Start(func(ctx context.Context, evt events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { 33 | return shim.handle(ctx, evt) 34 | }) 35 | return shim, nil 36 | } 37 | 38 | func (shim *HttpHandlerShim) handle(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { 39 | if !shim.initCalled { 40 | handler, err := shim.init() 41 | if err != nil { 42 | log.Printf("ERROR: %s", err.Error()) 43 | return events.APIGatewayProxyResponse{StatusCode: 500, Body: err.Error()}, err 44 | } 45 | shim.handler = handler 46 | shim.initCalled = true 47 | } 48 | 49 | var urlStr string 50 | if len(request.QueryStringParameters) != 0 { 51 | urlStr = fmt.Sprintf("%s?%s", request.Path, utils.QueryStringParams2Values(request.QueryStringParameters).Encode()) 52 | } else { 53 | urlStr = request.Path 54 | } 55 | requestUrl, err := url.ParseRequestURI(urlStr) 56 | if err != nil { 57 | log.Printf("ERROR: %s", err.Error()) 58 | return events.APIGatewayProxyResponse{StatusCode: 500, Body: err.Error()}, err 59 | } 60 | var bodyReader io.Reader 61 | bodyReader = strings.NewReader(request.Body) 62 | if request.IsBase64Encoded { 63 | bodyReader = base64.NewDecoder(base64.StdEncoding, bodyReader) 64 | } 65 | httpRequest := http.Request{ 66 | Method: request.HTTPMethod, 67 | URL: requestUrl, 68 | Proto: "HTTP/1.0", 69 | ProtoMajor: 1, 70 | ProtoMinor: 0, 71 | Header: utils.Headers2Header(request.Headers), 72 | Body: ioutil.NopCloser(bodyReader), 73 | ContentLength: int64(len(request.Body)), 74 | Close: false, 75 | Host: request.Headers["Host"], 76 | RemoteAddr: request.Headers["Host"], 77 | RequestURI: requestUrl.String(), 78 | } 79 | responseWriter, err := utils.NewLambdaResponseWriter() 80 | if err != nil { 81 | log.Printf("ERROR: %s", err.Error()) 82 | return events.APIGatewayProxyResponse{StatusCode: 500, Body: err.Error()}, nil 83 | } 84 | shim.handler.ServeHTTP(responseWriter, httpRequest.WithContext(ctx)) 85 | if responseWriter.ResponseBuffer.Len() > 0 { 86 | if _, hasContentType := responseWriter.Header()["Content-Type"]; !hasContentType { 87 | responseWriter.Header().Add("Content-Type", http.DetectContentType(responseWriter.ResponseBuffer.Bytes())) 88 | } 89 | } 90 | responseBody := responseWriter.ResponseBuffer.String() 91 | response := events.APIGatewayProxyResponse{ 92 | StatusCode: int(responseWriter.StatusCode), 93 | Body: responseBody, 94 | Headers: utils.Header2Headers(responseWriter.Header()), 95 | } 96 | return response, nil 97 | } 98 | -------------------------------------------------------------------------------- /eawsy/shim.go: -------------------------------------------------------------------------------- 1 | package eawsy 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/danapsimer/aws-api-to-lambda-shim/utils" 8 | "github.com/eawsy/aws-lambda-go/service/lambda/runtime" 9 | "io" 10 | "io/ioutil" 11 | "log" 12 | "net/http" 13 | "net/url" 14 | "strings" 15 | ) 16 | 17 | type ShimInitFunc func() (http.Handler, error) 18 | 19 | type HttpHandlerShim struct { 20 | init ShimInitFunc 21 | initCalled bool 22 | handler http.Handler 23 | } 24 | 25 | func NewHttpHandlerShim(init ShimInitFunc) (*HttpHandlerShim, error) { 26 | shim := &HttpHandlerShim{ 27 | init: init, 28 | initCalled: false, 29 | handler: nil, 30 | } 31 | runtime.HandleFunc(func(evt json.RawMessage, ctx *runtime.Context) (interface{}, error) { 32 | return shim.handle(evt, ctx) 33 | }) 34 | return shim, nil 35 | } 36 | 37 | type identity struct { 38 | ApiKey string 39 | UserArn string 40 | AccessKey string 41 | Caller string 42 | UserAgent string 43 | User string 44 | CognitoIdentityPoolId string 45 | CognitoIdentityId string 46 | CognitoAuthenticationProvider string 47 | SourceId string 48 | AccountId string 49 | } 50 | 51 | type requestContext struct { 52 | ResourceId string 53 | ApiId string 54 | ResourcePath string 55 | HttpMethod string 56 | RequestId string 57 | AccountId string 58 | Identity identity 59 | Stage string 60 | } 61 | 62 | type apiGatewayMessage struct { 63 | Body string 64 | Resource string 65 | RequestContext requestContext 66 | QueryStringParameters map[string]string 67 | HttpMethod string 68 | PathParameters map[string]string 69 | Headers map[string]string 70 | StageVariable map[string]string 71 | Path string 72 | IsBase64Encoded bool 73 | } 74 | 75 | type apiGatewayResponse struct { 76 | StatusCode int32 `json:"statusCode"` 77 | Headers map[string]string `json:"headers,omitempty"` 78 | Body string `json:"body,omitempty"` 79 | } 80 | 81 | func (shim *HttpHandlerShim) handle(evt json.RawMessage, ctx *runtime.Context) (interface{}, error) { 82 | if !shim.initCalled { 83 | handler, err := shim.init() 84 | if err != nil { 85 | log.Printf("ERROR: %s", err.Error()) 86 | return nil, err 87 | } 88 | shim.handler = handler 89 | shim.initCalled = true 90 | } 91 | 92 | log.Printf("payload: %s", string(evt)) 93 | var msg apiGatewayMessage 94 | err := json.Unmarshal(evt, &msg) 95 | if err != nil { 96 | log.Printf("ERROR: %s", err.Error()) 97 | return apiGatewayResponse{StatusCode: 500, Body: err.Error()}, nil 98 | } 99 | 100 | var urlStr string 101 | if len(msg.QueryStringParameters) != 0 { 102 | urlStr = fmt.Sprintf("%s?%s", msg.Path, utils.QueryStringParams2Values(msg.QueryStringParameters).Encode()) 103 | } else { 104 | urlStr = msg.Path 105 | } 106 | url, err := url.ParseRequestURI(urlStr) 107 | if err != nil { 108 | log.Printf("ERROR: %s", err.Error()) 109 | return apiGatewayResponse{StatusCode: 500, Body: err.Error()}, nil 110 | } 111 | var bodyReader io.Reader 112 | bodyReader = strings.NewReader(msg.Body) 113 | if msg.IsBase64Encoded { 114 | bodyReader = base64.NewDecoder(base64.StdEncoding, bodyReader) 115 | } 116 | //log.Printf("url parsed: %v", url) 117 | httpRequest := http.Request{ 118 | Method: msg.HttpMethod, 119 | URL: url, 120 | Proto: "HTTP/1.0", 121 | ProtoMajor: 1, 122 | ProtoMinor: 0, 123 | Header: utils.Headers2Header(msg.Headers), 124 | Body: ioutil.NopCloser(bodyReader), 125 | ContentLength: int64(len(msg.Body)), 126 | Close: false, 127 | Host: msg.Headers["Host"], 128 | RemoteAddr: msg.Headers["Host"], 129 | RequestURI: url.String(), 130 | } 131 | //log.Printf("httpRequest created: %v", &httpRequest) 132 | responseWriter, err := utils.NewLambdaResponseWriter() 133 | if err != nil { 134 | log.Printf("ERROR: %s", err.Error()) 135 | return apiGatewayResponse{StatusCode: 500, Body: err.Error()}, nil 136 | } 137 | //log.Printf("calling service.Mux(%v,%v)", responseWriter, &httpRequest) 138 | shim.handler.ServeHTTP(responseWriter, &httpRequest) 139 | if responseWriter.ResponseBuffer.Len() > 0 { 140 | if _, hasContentType := responseWriter.Header()["Content-Type"]; !hasContentType { 141 | responseWriter.Header().Add("Content-Type", http.DetectContentType(responseWriter.ResponseBuffer.Bytes())) 142 | } 143 | } 144 | responseBody := responseWriter.ResponseBuffer.String() 145 | response := apiGatewayResponse{ 146 | StatusCode: int32(responseWriter.StatusCode), 147 | Body: responseBody, 148 | Headers: utils.Header2Headers(responseWriter.Header()), 149 | } 150 | //log.Printf("Response: %v", &response) 151 | return &response, nil 152 | } 153 | -------------------------------------------------------------------------------- /examples/helloWorld/Readme.md: -------------------------------------------------------------------------------- 1 | # Hello World Example for aws-lambda-shim 2 | 3 | This directory contains a simple "Hello, World" webservice that can be 4 | deployed to either AWS Lambda and accessed through AWS Api Gateway or 5 | run standalone as a traditional go HTTP server. -------------------------------------------------------------------------------- /examples/helloWorld/aws/Makefile: -------------------------------------------------------------------------------- 1 | AWS_ACCOUNT_ID := $(shell aws iam get-user | jq -r '.User.Arn' | cut -d : -f 5) 2 | $(info AWS_ACCOUNT_ID = '$(AWS_ACCOUNT_ID)') 3 | 4 | AWS_ROLE := arn:aws:iam::$(AWS_ACCOUNT_ID):role/lambda_basic_execution 5 | 6 | build: 7 | GOOS=linux go build -o handler 8 | 9 | pack: 10 | zip handler.zip handler 11 | 12 | clean: 13 | @rm -rf handler.zip handler 14 | 15 | create: 16 | @aws lambda create-function \ 17 | --region us-east-1 \ 18 | --function-name hello-world-api-go \ 19 | --zip-file fileb://handler.zip \ 20 | --runtime go1.x \ 21 | --role $(AWS_ROLE) \ 22 | --handler handler 23 | 24 | update: 25 | @aws lambda update-function-code --function-name hello-world-api-go --zip-file fileb://handler.zip -------------------------------------------------------------------------------- /examples/helloWorld/aws/handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/danapsimer/aws-api-to-lambda-shim/aws" 5 | "github.com/danapsimer/aws-api-to-lambda-shim/examples/helloWorld/hello" 6 | ) 7 | 8 | func init() { 9 | aws.NewHttpHandlerShim(hello.InitHandler) 10 | } 11 | 12 | func main() { 13 | } 14 | -------------------------------------------------------------------------------- /examples/helloWorld/eawsy/Makefile: -------------------------------------------------------------------------------- 1 | # System build 2 | 3 | build: 4 | go build -buildmode=c-shared -ldflags="-w -s" -o handler.so 5 | chown `stat -c "%u:%g" .` handler.so 6 | 7 | pack: 8 | zip handler.zip handler.so 9 | chown `stat -c "%u:%g" .` handler.zip 10 | 11 | # Docker build for OS X or Windoze 12 | 13 | dbuild: 14 | @docker run --rm \ 15 | -v $(GOPATH):/go \ 16 | -w /go/src/github.com/danapsimer/aws-api-to-lambda-shim/examples/helloWorld/lambda \ 17 | eawsy/aws-lambda-go make build 18 | 19 | dpack: 20 | @docker run --rm \ 21 | -v $(GOPATH):/go \ 22 | -w /go/src/github.com/danapsimer/aws-api-to-lambda-shim/examples/helloWorld/lambda \ 23 | eawsy/aws-lambda-go make pack 24 | 25 | clean: 26 | @rm -rf handler.zip handler.so 27 | 28 | deploy: 29 | @aws lambda update-function-code --function-name hello-world-api --zip-file fileb://handler.zip 30 | -------------------------------------------------------------------------------- /examples/helloWorld/eawsy/handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/danapsimer/aws-api-to-lambda-shim/eawsy" 5 | "github.com/danapsimer/aws-api-to-lambda-shim/examples/helloWorld/hello" 6 | ) 7 | 8 | func init() { 9 | eawsy.NewHttpHandlerShim(hello.InitHandler) 10 | } 11 | 12 | func main() { 13 | } 14 | -------------------------------------------------------------------------------- /examples/helloWorld/hello/hello.go: -------------------------------------------------------------------------------- 1 | package hello 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "regexp" 8 | ) 9 | 10 | var ( 11 | helloMatcher = regexp.MustCompile("/hello/(.*)") 12 | ) 13 | 14 | type greeting struct { 15 | Greeting string `json:"greeting,omitempty"` 16 | } 17 | 18 | func InitHandler() (http.Handler, error) { 19 | mux := http.NewServeMux() 20 | mux.HandleFunc("/hello/", func(w http.ResponseWriter, req *http.Request) { 21 | matches := helloMatcher.FindAllStringSubmatch(req.URL.Path, -1) 22 | w.Header().Add("Content-Type", "application/json") 23 | w.WriteHeader(http.StatusOK) 24 | name := matches[0][1] 25 | if name == "" { 26 | name = "World" 27 | } 28 | greeting := greeting{fmt.Sprintf("Hello, %s!", name)} 29 | jsonEncoder := json.NewEncoder(w) 30 | jsonEncoder.Encode(greeting) 31 | }) 32 | return mux, nil 33 | } 34 | -------------------------------------------------------------------------------- /examples/helloWorld/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/danapsimer/aws-api-to-lambda-shim/examples/helloWorld/hello" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | handler, _ := hello.InitHandler() 11 | log.Fatal(http.ListenAndServe(":8080", handler)) 12 | } 13 | -------------------------------------------------------------------------------- /examples/helloWorld/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "version": "2016-09-12T17:50:37Z", 5 | "title": "HelloWorldLambdaProxyIntegration" 6 | }, 7 | "basePath": "/hello", 8 | "schemes": [ 9 | "https" 10 | ], 11 | "paths": { 12 | "/{proxy+}": { 13 | "x-amazon-apigateway-any-method": { 14 | "produces": [ 15 | "application/json" 16 | ], 17 | "parameters": [ 18 | { 19 | "name": "proxy", 20 | "in": "path", 21 | "required": true, 22 | "type": "string" 23 | } 24 | ], 25 | "responses": {}, 26 | "x-amazon-apigateway-integration": { 27 | "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:${AWS_ACCOUNT_ID}:function:hello-world-api/invocations", 28 | "passthroughBehavior": "when_no_match", 29 | "httpMethod": "POST", 30 | "type": "aws_proxy" 31 | } 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/danapsimer/aws-api-to-lambda-shim 2 | 3 | require ( 4 | github.com/aws/aws-lambda-go v1.6.0 5 | github.com/davecgh/go-spew v1.1.1 // indirect 6 | github.com/eawsy/aws-lambda-go v0.0.0-20170302222045-d67ea54b7d71 7 | github.com/pmezard/go-difflib v1.0.0 // indirect 8 | github.com/stretchr/testify v1.2.2 // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/aws/aws-lambda-go v1.6.0 h1:T+u/g79zPKw1oJM7xYhvpq7i4Sjc0iVsXZUaqRVVSOg= 2 | github.com/aws/aws-lambda-go v1.6.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/eawsy/aws-lambda-go v0.0.0-20170302222045-d67ea54b7d71 h1:6rRqlAsc66muRtZS+5i9j0NS63/sYWWqWcHh02cWWzs= 6 | github.com/eawsy/aws-lambda-go v0.0.0-20170302222045-d67ea54b7d71/go.mod h1:4gET2E5JmpmYq9yc/RxellpusH7Zf/nYG/yUCeXkZ9w= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 10 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 11 | -------------------------------------------------------------------------------- /utils/adapters.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | "net/url" 7 | ) 8 | 9 | type lambdaResponseWriter struct { 10 | header http.Header 11 | StatusCode int 12 | ResponseBuffer bytes.Buffer 13 | } 14 | 15 | func NewLambdaResponseWriter() (*lambdaResponseWriter, error) { 16 | return &lambdaResponseWriter{ 17 | header: make(map[string][]string), 18 | StatusCode: 0, 19 | }, nil 20 | } 21 | 22 | func (w *lambdaResponseWriter) Header() http.Header { 23 | return w.header 24 | } 25 | 26 | func (w *lambdaResponseWriter) Write(bytes []byte) (int, error) { 27 | if w.StatusCode == 0 { 28 | w.StatusCode = 200 29 | } 30 | bytesWritten, err := w.ResponseBuffer.Write(bytes) 31 | return bytesWritten, err 32 | } 33 | 34 | func (w *lambdaResponseWriter) WriteHeader(statusCode int) { 35 | w.StatusCode = statusCode 36 | } 37 | 38 | func QueryStringParams2Values(qsp map[string]string) url.Values { 39 | if qsp == nil { 40 | return nil 41 | } 42 | values := url.Values{} 43 | for k, v := range qsp { 44 | values.Add(k, v) 45 | } 46 | return values 47 | } 48 | 49 | func Headers2Header(headers map[string]string) http.Header { 50 | if headers == nil { 51 | return nil 52 | } 53 | values := http.Header{} 54 | for k, v := range headers { 55 | values.Add(k, v) 56 | } 57 | return values 58 | } 59 | 60 | func Header2Headers(header http.Header) map[string]string { 61 | if header == nil { 62 | return nil 63 | } 64 | values := make(map[string]string) 65 | for k, v := range header { 66 | values[k] = v[0] 67 | } 68 | return values 69 | } 70 | --------------------------------------------------------------------------------