Initial commit of lambdarouter package including first iteration created; no docs; no tests as of yet
This commit is contained in:
commit
0b30efee89
|
@ -0,0 +1 @@
|
|||
vendor
|
|
@ -0,0 +1,21 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/armon/go-radix"
|
||||
packages = ["."]
|
||||
revision = "1fca145dffbcaa8fe914309b1ec0cfc67500fe61"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/aws/aws-lambda-go"
|
||||
packages = ["events"]
|
||||
revision = "4d30d0ff60440c2d0480a15747c96ee71c3c53d4"
|
||||
version = "v1.2.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "35d3fdde995b8cf314934259f07ffb089e30092e11fb8e404ea398ce1c76a431"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
|
@ -0,0 +1,38 @@
|
|||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/armon/go-radix"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/aws/aws-lambda-go"
|
||||
version = "1.2.0"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
|
@ -0,0 +1,2 @@
|
|||
# lambdarouter
|
||||
This package will become a fully featured AWS Lambda function router, able to respond to HTTP, Schedule, Cognito, and SNS events. It will also support middleware interfacing.
|
|
@ -0,0 +1,168 @@
|
|||
package lambdarouter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
radix "github.com/armon/go-radix"
|
||||
"github.com/aws/aws-lambda-go/events"
|
||||
)
|
||||
|
||||
// Method constants.
|
||||
const (
|
||||
POST = http.MethodPost
|
||||
GET = http.MethodGet
|
||||
PUT = http.MethodPut
|
||||
DELETE = http.MethodDelete
|
||||
)
|
||||
|
||||
// HandlerRequest ...
|
||||
type HandlerRequest struct {
|
||||
Claims map[string]string
|
||||
Path map[string]string
|
||||
QryStr map[string]string
|
||||
Request *events.APIGatewayProxyRequest
|
||||
}
|
||||
|
||||
// HandlerResponse ...
|
||||
type HandlerResponse struct {
|
||||
Status int
|
||||
Body []byte
|
||||
Err error
|
||||
}
|
||||
|
||||
// Handler ...
|
||||
type Handler func(req *HandlerRequest, res *HandlerResponse)
|
||||
|
||||
// Router ...
|
||||
type Router struct {
|
||||
request *events.APIGatewayProxyRequest
|
||||
endpoints map[string]*radix.Tree
|
||||
params map[string]string
|
||||
svcprefix string
|
||||
}
|
||||
|
||||
// NOTE: Begin router methods.
|
||||
|
||||
// New ...
|
||||
func New(r *events.APIGatewayProxyRequest, svcprefix string) *Router {
|
||||
return &Router{
|
||||
request: r,
|
||||
endpoints: map[string]*radix.Tree{
|
||||
POST: radix.New(),
|
||||
GET: radix.New(),
|
||||
PUT: radix.New(),
|
||||
DELETE: radix.New(),
|
||||
},
|
||||
params: map[string]string{},
|
||||
svcprefix: svcprefix,
|
||||
}
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (r *Router) Get(route string, handler Handler) {
|
||||
r.addEndpoint(GET, route, handler)
|
||||
}
|
||||
|
||||
// Post ...
|
||||
func (r *Router) Post(route string, handler Handler) {
|
||||
r.addEndpoint(POST, route, handler)
|
||||
}
|
||||
|
||||
// Put ...
|
||||
func (r *Router) Put(route string, handler Handler) {
|
||||
r.addEndpoint(PUT, route, handler)
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (r *Router) Delete(route string, handler Handler) {
|
||||
r.addEndpoint(DELETE, route, handler)
|
||||
}
|
||||
|
||||
// Respond ...
|
||||
func (r *Router) Respond() events.APIGatewayProxyResponse {
|
||||
var (
|
||||
handlerInterface interface{}
|
||||
ok bool
|
||||
|
||||
endpointTree = r.endpoints[r.request.HTTPMethod]
|
||||
path = strings.TrimPrefix(r.request.Path, "/"+r.svcprefix)
|
||||
response = events.APIGatewayProxyResponse{}
|
||||
)
|
||||
log.Printf("path: %+v", path)
|
||||
|
||||
for k := range r.params {
|
||||
p := strings.TrimPrefix(k, "{")
|
||||
p = strings.TrimSuffix(p, "}")
|
||||
if r.request.PathParameters[p] != "" {
|
||||
path = strings.Replace(path, r.request.PathParameters[p], k, -1)
|
||||
}
|
||||
}
|
||||
log.Printf("path: %+v", path)
|
||||
|
||||
if handlerInterface, ok = endpointTree.Get(path); !ok {
|
||||
respbody, _ := json.Marshal(map[string]string{"error": "no route matching path found"})
|
||||
|
||||
response.StatusCode = http.StatusNotFound
|
||||
response.Body = string(respbody)
|
||||
return response
|
||||
}
|
||||
|
||||
handler := handlerInterface.(Handler)
|
||||
|
||||
req := &HandlerRequest{
|
||||
Claims: r.request.RequestContext.Authorizer["claims"].(map[string]string),
|
||||
Path: r.request.PathParameters,
|
||||
QryStr: r.request.QueryStringParameters,
|
||||
Request: r.request,
|
||||
}
|
||||
res := &HandlerResponse{}
|
||||
|
||||
handler(req, res)
|
||||
status, respbody, err := res.deconstruct()
|
||||
|
||||
if err != nil {
|
||||
respbody, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||
if strings.Contains(err.Error(), "record not found") {
|
||||
status = 204
|
||||
} else if status < 400 {
|
||||
status = 400
|
||||
}
|
||||
|
||||
response.StatusCode = status
|
||||
response.Body = string(respbody)
|
||||
return response
|
||||
}
|
||||
|
||||
response.StatusCode = status
|
||||
response.Body = string(respbody)
|
||||
return response
|
||||
}
|
||||
|
||||
// NOTE: Begin helper functions.
|
||||
func stripSlashesAndSplit(s string) []string {
|
||||
s = strings.TrimPrefix(s, "/")
|
||||
s = strings.TrimSuffix(s, "/")
|
||||
return strings.Split(s, "/")
|
||||
}
|
||||
|
||||
func (res *HandlerResponse) deconstruct() (int, []byte, error) {
|
||||
return res.Status, res.Body, res.Err
|
||||
}
|
||||
|
||||
func (r *Router) addEndpoint(method string, route string, handler Handler) {
|
||||
if _, overwrite := r.endpoints[method].Insert(route, handler); overwrite {
|
||||
panic("endpoint already existent")
|
||||
}
|
||||
|
||||
rtearr := stripSlashesAndSplit(route)
|
||||
for _, v := range rtearr {
|
||||
if strings.HasPrefix(v, "{") {
|
||||
r.params[v] = "" // adding params as keys with {brackets}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("router: %+v", *r)
|
||||
}
|
Loading…
Reference in New Issue