-
Notifications
You must be signed in to change notification settings - Fork 0
/
apigateway.go
143 lines (118 loc) · 4.18 KB
/
apigateway.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package apigateway // import "wiliam.dev/apigateway"
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"net/url"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/julienschmidt/httprouter"
)
// Gateway API
type Gateway struct {
router *httprouter.Router
}
// Handle registers a new request handle with the given path and method.
func (g *Gateway) Handle(method, path string, handler http.Handler) {
g.router.Handler(method, path, handler)
}
// Router return API gateway router
func (g *Gateway) Router() *httprouter.Router {
return g.router
}
// New API gateway
func New() *Gateway {
return &Gateway{router: httprouter.New()}
}
// SNSReverseProxy AWS simple notification proxy
type SNSReverseProxy struct {
TopicArn string
Config *aws.Config
RequestTranslator func(*http.Request)
}
func (p *SNSReverseProxy) errorHandler(rw http.ResponseWriter, req *http.Request, err error) {
log.Println(err)
rw.WriteHeader(http.StatusBadGateway)
}
func (p *SNSReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if p.RequestTranslator != nil {
p.RequestTranslator(req)
}
body, err := ioutil.ReadAll(req.Body)
if err != nil {
defer req.Body.Close()
panic(http.ErrAbortHandler)
}
req.Body.Close()
s := session.Must(session.NewSession())
var c *sns.SNS
c = sns.New(s)
if p.Config.Endpoint != (aws.Config{}.Endpoint) {
c = sns.New(s, p.Config)
}
message, err := json.Marshal(map[string]string{"default": string(body)})
if err != nil {
p.errorHandler(rw, req, err)
}
input := &sns.PublishInput{
Message: aws.String(string(message)),
MessageStructure: aws.String("json"),
TopicArn: aws.String(p.TopicArn),
}
ctx := req.Context()
_, err = c.PublishWithContext(ctx, input)
if err != nil {
p.errorHandler(rw, req, err)
}
rw.WriteHeader(http.StatusAccepted)
}
// NewReverseProxy returns a new ReverseProxy that routes URLs to the scheme,
// host, and base path provided in target.
func NewReverseProxy(target *url.URL, responseTranslator func(*http.Response) error, requestTranslator func(*http.Request)) *httputil.ReverseProxy {
director := func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path = target.Path
req.Host = target.Host
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
targetQuery := target.RawQuery
if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
if _, ok := req.Header["User-Agent"]; !ok {
req.Header.Set("User-Agent", "")
}
if requestTranslator != nil {
requestTranslator(req)
}
}
if responseTranslator != nil {
return &httputil.ReverseProxy{ModifyResponse: responseTranslator, Director: director}
}
return &httputil.ReverseProxy{Director: director}
}
// NewPassthroughReverseProxy redirect client call to backend target
func NewPassthroughReverseProxy(target *url.URL) *httputil.ReverseProxy {
return NewReverseProxy(target, nil, nil)
}
// NewResponseTranslatorReverseProxy modifies response before respond it to clients
func NewResponseTranslatorReverseProxy(target *url.URL, responseTranslator func(*http.Response) error) *httputil.ReverseProxy {
return NewReverseProxy(target, responseTranslator, nil)
}
// NewRequestTranslatorReverseProxy modifies the request into a new request before send to backend target
func NewRequestTranslatorReverseProxy(target *url.URL, requestTranslator func(*http.Request)) *httputil.ReverseProxy {
return NewReverseProxy(target, nil, requestTranslator)
}
// NewSNSPassthroughReverseProxy publishes request body to SNS topic
func NewSNSPassthroughReverseProxy(topicArn string, config *aws.Config) *SNSReverseProxy {
return &SNSReverseProxy{TopicArn: topicArn, Config: config}
}
// NewSNSRequestTranslatorReverseProxy publishes modified request body to SNS topic
func NewSNSRequestTranslatorReverseProxy(topicArn string, config *aws.Config, requestTranslator func(*http.Request)) *SNSReverseProxy {
return &SNSReverseProxy{TopicArn: topicArn, Config: config, RequestTranslator: requestTranslator}
}