Skip to content

Commit 1c69ba9

Browse files
committed
v0.1.0
1 parent 245239d commit 1c69ba9

File tree

12 files changed

+885
-0
lines changed

12 files changed

+885
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea/

README.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# aws-lambda-go-http-adapter
2+
Simple HTTP adapter for AWS Lambda
3+
4+
## Builtin support for these event formats:
5+
- AWS Lambda Function URL
6+
- API Gateway (v1)
7+
- API Gateway (v2)
8+
9+
## Builtin support for these HTTP frameworks:
10+
- `net/http`
11+
- [Echo](https://github.com/labstack/echo)
12+
- [Fiber](https://github.com/gofiber/fiber)
13+
14+
## Usage
15+
### Creating the Adapter
16+
#### net/http
17+
Build tag: `http_adapter_vanilla`
18+
```golang
19+
package main
20+
21+
import (
22+
"github.com/its-felix/aws-lambda-go-http-adapter/adapter/vanilla"
23+
"net/http"
24+
)
25+
26+
func main() {
27+
mux := http.NewServeMux()
28+
mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
29+
w.WriteHeader(http.StatusOK)
30+
_, _ = w.Write([]byte("pong"))
31+
})
32+
33+
adapter := vanilla.NewAdapter(mux)
34+
}
35+
```
36+
37+
#### Echo
38+
Build tag: `http_adapter_echo`
39+
```golang
40+
package main
41+
42+
import (
43+
"github.com/labstack/echo/v4"
44+
echoadapter "github.com/its-felix/aws-lambda-go-http-adapter/adapter/echo"
45+
"net/http"
46+
)
47+
48+
func main() {
49+
e := echo.New()
50+
e.Add("GET", "/ping", func(c echo.Context) error {
51+
return c.String(200, "pong")
52+
})
53+
54+
adapter := echoadapter.NewAdapter(e)
55+
}
56+
```
57+
58+
#### Fiber
59+
Build tag: `http_adapter_fiber`
60+
```golang
61+
package main
62+
63+
import (
64+
"github.com/gofiber/fiber/v2"
65+
fiberadapter "github.com/its-felix/aws-lambda-go-http-adapter/adapter/fiber"
66+
"net/http"
67+
)
68+
69+
func main() {
70+
app := fiber.New()
71+
app.Get("/ping", func(ctx *fiber.Ctx) error {
72+
return ctx.SendString("pong")
73+
})
74+
75+
adapter := fiberadapter.NewAdapter(app)
76+
}
77+
```
78+
79+
### Creating the Handler
80+
#### API Gateway V1
81+
```golang
82+
package main
83+
84+
import (
85+
"github.com/aws/aws-lambda-go/lambda"
86+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
87+
)
88+
89+
func main() {
90+
adapter := [...] // see above
91+
h := handler.NewAPIGatewayV1Handler(adapter)
92+
93+
lambda.Start(h)
94+
}
95+
```
96+
97+
#### API Gateway V2
98+
```golang
99+
package main
100+
101+
import (
102+
"github.com/aws/aws-lambda-go/lambda"
103+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
104+
)
105+
106+
func main() {
107+
adapter := [...] // see above
108+
h := handler.NewAPIGatewayV2Handler(adapter)
109+
110+
lambda.Start(h)
111+
}
112+
```
113+
114+
#### Lambda Function URL
115+
```golang
116+
package main
117+
118+
import (
119+
"github.com/aws/aws-lambda-go/lambda"
120+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
121+
)
122+
123+
func main() {
124+
adapter := [...] // see above
125+
h := handler.NewFunctionURLHandler(adapter)
126+
127+
lambda.Start(h)
128+
}
129+
```
130+
131+
### Accessing the source event
132+
#### Fiber
133+
```golang
134+
package main
135+
136+
import (
137+
"github.com/aws/aws-lambda-go/events"
138+
"github.com/gofiber/fiber/v2"
139+
fiberadapter "github.com/its-felix/aws-lambda-go-http-adapter/adapter/fiber"
140+
)
141+
142+
func main() {
143+
app := fiber.New()
144+
app.Get("/ping", func(ctx *fiber.Ctx) error {
145+
event := fiberadapter.GetSourceEvent(ctx)
146+
switch event := event.(type) {
147+
case events.APIGatewayProxyRequest:
148+
// do something
149+
case events.APIGatewayV2HTTPRequest:
150+
// do something
151+
case events.LambdaFunctionURLRequest:
152+
// do something
153+
}
154+
155+
return ctx.SendString("pong")
156+
})
157+
}
158+
```
159+
160+
#### Others
161+
```golang
162+
package main
163+
164+
import (
165+
"github.com/aws/aws-lambda-go/events"
166+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
167+
"net/http"
168+
)
169+
170+
func main() {
171+
mux := http.NewServeMux()
172+
mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
173+
event := handler.GetSourceEvent(r.Context())
174+
switch event := event.(type) {
175+
case events.APIGatewayProxyRequest:
176+
// do something
177+
case events.APIGatewayV2HTTPRequest:
178+
// do something
179+
case events.LambdaFunctionURLRequest:
180+
// do something
181+
}
182+
183+
w.WriteHeader(http.StatusOK)
184+
_, _ = w.Write([]byte("pong"))
185+
})
186+
}
187+
```
188+
189+
### Handle panics
190+
To handle panics, first create the handler as described above. You can then wrap the handler to handle panics like so:
191+
```golang
192+
package main
193+
194+
import (
195+
"context"
196+
"github.com/aws/aws-lambda-go/lambda"
197+
"github.com/aws/aws-lambda-go/events"
198+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
199+
)
200+
201+
func main() {
202+
adapter := [...] // see above
203+
h := [...] // see above
204+
h = WrapWithRecover(h, func(ctx context.Context, event events.APIGatewayV2HTTPRequest, panicValue any) (events.APIGatewayV2HTTPResponse, error) {
205+
return events.APIGatewayV2HTTPResponse{
206+
StatusCode: 500,
207+
Headers: make(map[string]string),
208+
Body: fmt.Sprintf("Unexpected error: %v", panicValue),
209+
}, nil
210+
})
211+
212+
lambda.Start(h)
213+
}
214+
```
215+
216+
## Extending for other lambda event formats:
217+
Have a look at the existing event handlers:
218+
- [API Gateway V1](./handler/apigwv1.go)
219+
- [API Gateway V2](./handler/apigwv2.go)
220+
- [Lambda Function URL](./handler/functionurl.go)
221+
222+
## Extending for other frameworks
223+
Have a look at the existing adapters:
224+
- [net/http](./adapter/vanilla/vanilla.go)
225+
- [Echo](./adapter/echo/echo.go)
226+
- [Fiber](./adapter/fiber/fiber.go)

adapter/echo/echo.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//go:build http_adapter_echo
2+
// +build http_adapter_echo
3+
4+
package echo
5+
6+
import (
7+
"context"
8+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
9+
"github.com/labstack/echo/v4"
10+
"net/http"
11+
)
12+
13+
type adapter struct {
14+
echo *echo.Echo
15+
}
16+
17+
func (a adapter) adapterFunc(ctx context.Context, r *http.Request, w http.ResponseWriter) error {
18+
a.echo.ServeHTTP(w, r)
19+
return nil
20+
}
21+
22+
func NewAdapter(delegate *echo.Echo) handler.AdapterFunc {
23+
return adapter{delegate}.adapterFunc
24+
}

adapter/fiber/fiber.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//go:build http_adapter_fiber
2+
// +build http_adapter_fiber
3+
4+
package fiber
5+
6+
import (
7+
"context"
8+
"github.com/gofiber/fiber/v2"
9+
"github.com/gofiber/fiber/v2/utils"
10+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
11+
"github.com/valyala/fasthttp"
12+
"io"
13+
"net"
14+
"net/http"
15+
"strings"
16+
)
17+
18+
const sourceEventUserValueKey = "github.com/its-felix/aws-lambda-go-adapter-fiber::sourceEvent"
19+
20+
type adapter struct {
21+
app *fiber.App
22+
}
23+
24+
func (a adapter) adapterFunc(ctx context.Context, r *http.Request, w http.ResponseWriter) error {
25+
httpReq := fasthttp.AcquireRequest()
26+
defer fasthttp.ReleaseRequest(httpReq)
27+
28+
// protocol, method, uri, host
29+
httpReq.Header.SetProtocol(r.Proto)
30+
httpReq.Header.SetMethod(r.Method)
31+
httpReq.SetRequestURI(r.RequestURI)
32+
httpReq.SetHost(r.Host)
33+
34+
// body
35+
if r.Body != nil {
36+
defer r.Body.Close()
37+
written, err := io.Copy(httpReq.BodyWriter(), r.Body)
38+
if err != nil {
39+
return err
40+
}
41+
42+
httpReq.Header.SetContentLength(int(written))
43+
}
44+
45+
// headers
46+
for k, values := range r.Header {
47+
for _, v := range values {
48+
switch k {
49+
case fiber.HeaderHost,
50+
fiber.HeaderContentType,
51+
fiber.HeaderUserAgent,
52+
fiber.HeaderContentLength,
53+
fiber.HeaderConnection:
54+
httpReq.Header.Set(k, v)
55+
default:
56+
httpReq.Header.Add(k, v)
57+
}
58+
}
59+
}
60+
61+
// remoteAddr
62+
remoteAddr, err := net.ResolveTCPAddr("tcp", r.RemoteAddr)
63+
if err != nil {
64+
return err
65+
}
66+
67+
var fctx fasthttp.RequestCtx
68+
fctx.Init(httpReq, remoteAddr, nil)
69+
fctx.SetUserValue(sourceEventUserValueKey, handler.GetSourceEvent(ctx))
70+
71+
a.app.Handler()(&fctx)
72+
73+
fctx.Response.Header.VisitAll(func(key, value []byte) {
74+
k := utils.UnsafeString(key)
75+
76+
for _, v := range strings.Split(utils.UnsafeString(value), ",") {
77+
w.Header().Add(k, v)
78+
}
79+
})
80+
81+
w.WriteHeader(fctx.Response.StatusCode())
82+
_, _ = w.Write(fctx.Response.Body())
83+
84+
return nil
85+
}
86+
87+
func NewAdapter(delegate *fiber.App) handler.AdapterFunc {
88+
return adapter{delegate}.adapterFunc
89+
}
90+
91+
func GetSourceEvent(ctx *fiber.Ctx) any {
92+
return ctx.Context().UserValue(sourceEventUserValueKey)
93+
}

adapter/vanilla/vanilla.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//go:build http_adapter_vanilla
2+
// +build http_adapter_vanilla
3+
4+
package vanilla
5+
6+
import (
7+
"context"
8+
"github.com/its-felix/aws-lambda-go-http-adapter/handler"
9+
"net/http"
10+
)
11+
12+
type adapter struct {
13+
http.Handler
14+
}
15+
16+
func (a adapter) adapterFunc(ctx context.Context, r *http.Request, w http.ResponseWriter) error {
17+
a.ServeHTTP(w, r)
18+
return nil
19+
}
20+
21+
func NewAdapter(delegate http.Handler) handler.AdapterFunc {
22+
return adapter{delegate}.adapterFunc
23+
}

0 commit comments

Comments
 (0)