minke-generator-go 0.8.7 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +3 -1
  3. data/lib/generators/gomicroservice/scaffold/Makefile.erb +9 -0
  4. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/.gitignore +0 -0
  5. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/Gemfile +0 -0
  6. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/config.yml.erb +12 -3
  7. data/lib/generators/gomicroservice/scaffold/_minke/consul_keys.yml.erb +5 -0
  8. data/lib/generators/gomicroservice/scaffold/{_build/dockercompose/<%= application_name %>/docker-no-server.yml.erb → _minke/dockercompose/<%= application_name %>/docker-compose-no-server.yml.erb } +0 -8
  9. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/dockercompose/<%= application_name %>/docker-compose.yml.erb +0 -9
  10. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/dockerfile/<%= application_name %>/Dockerfile.erb +3 -6
  11. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/dockerfile/<%= application_name %>/config.ctmpl.erb +0 -1
  12. data/lib/generators/gomicroservice/scaffold/_minke/dockerfile/<%= application_name %>/entrypoint.sh.erb +3 -0
  13. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/features/health.feature +0 -0
  14. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/features/steps/http.rb +0 -0
  15. data/lib/generators/gomicroservice/scaffold/{_build → _minke}/features/support/env.rb.erb +0 -0
  16. data/lib/generators/gomicroservice/scaffold/config.json +3 -0
  17. data/lib/generators/gomicroservice/scaffold/glide.yaml.erb +1 -7
  18. data/lib/generators/gomicroservice/scaffold/global/global.go +5 -3
  19. data/lib/generators/gomicroservice/scaffold/handlers/echo.go.erb +16 -17
  20. data/lib/generators/gomicroservice/scaffold/handlers/echo_test.go.erb +12 -49
  21. data/lib/generators/gomicroservice/scaffold/handlers/health.go.erb +14 -38
  22. data/lib/generators/gomicroservice/scaffold/handlers/health_test.go.erb +9 -45
  23. data/lib/generators/gomicroservice/scaffold/handlers/middleware_requestvalidation.go.erb +48 -29
  24. data/lib/generators/gomicroservice/scaffold/handlers/middleware_requestvalidation_test.go.erb +21 -28
  25. data/lib/generators/gomicroservice/scaffold/handlers/mockHandler.go.erb +12 -0
  26. data/lib/generators/gomicroservice/scaffold/handlers/xx_router.go.erb +9 -19
  27. data/lib/generators/gomicroservice/scaffold/main.go.erb +11 -42
  28. data/lib/generators/gomicroservice/version.rb +1 -1
  29. metadata +19 -26
  30. data/lib/generators/gomicroservice/scaffold/_build/Rakefile +0 -4
  31. data/lib/generators/gomicroservice/scaffold/_build/consul_keys.yml.erb +0 -13
  32. data/lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/.s6-svscan/crash +0 -1
  33. data/lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/.s6-svscan/finish +0 -1
  34. data/lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/app/finish +0 -1
  35. data/lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/app/run.erb +0 -3
  36. data/lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/consul-template/finish +0 -1
  37. data/lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/consul-template/run.erb +0 -3
  38. data/lib/generators/gomicroservice/scaffold/_build/swagger_spec/swagger.yml.erb +0 -34
  39. data/lib/generators/gomicroservice/scaffold/handlers/const.go.erb +0 -12
  40. data/lib/generators/gomicroservice/scaffold/logging/StatsD.go +0 -6
  41. data/lib/generators/gomicroservice/scaffold/mocks/mocks.go +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7423ec4af6e0b2e68217c5e87fbe09c786b608ee
4
- data.tar.gz: a0ecfbcd25904c237a65ce7f4788a6697a44f1ac
3
+ metadata.gz: ccd7dbe99e9143f886b837464fdc16fa21cb940c
4
+ data.tar.gz: 9a3046943f8b56edc1205e8299df82a2db3a189d
5
5
  SHA512:
6
- metadata.gz: 2846f60293d99a5c73b1e08b1f7fff7a4d96b144493930bf3bc87eb511ecc048d8052c842cf3651142694b872dbe93e1120d9d3167281458a3f9dfc20e506b85
7
- data.tar.gz: 59908db1fd657c291037ce6f6c815ac0c58d2eebf1cd38474c56d9d59543573e7e4d29ccb0b9134918bb9753f7beb2084675dfa69a57ab6f7d662b4b9c66b838
6
+ metadata.gz: c5f0153adec63eb06bc0a8c3cd1365d4ad4d8814680325b745dd6714f22759d9f19e1684092fad0a485af104c06b71a1d47a37dc0c3d6e4b9c1ccc1b716b72f4
7
+ data.tar.gz: 704ef8ae332a864bcf695d0ded61ec7889c29cfe6e55a0d84580724007b822a88f87b58efbac52748d07d5dfc0c45ec4be03ed0cc801b118486c2e77d155125a
data/Dockerfile CHANGED
@@ -3,7 +3,9 @@ FROM golang:alpine
3
3
  # install curl
4
4
  RUN apk update && \
5
5
  apk add curl && \
6
- apk add git
6
+ apk add git && \
7
+ apk add openssh-client && \
8
+ apk add make
7
9
 
8
10
  # install Glide
9
11
  RUN go get -u github.com/Masterminds/glide
@@ -0,0 +1,9 @@
1
+ build:
2
+ go build -o <%= application_name %> ./main.go
3
+
4
+ run: build
5
+ ./<%= application_name %> ./config.json /
6
+
7
+ test:
8
+ go test -v -race $(shell go list ./... | grep -v /vendor/)
9
+
@@ -21,9 +21,6 @@ build:
21
21
  -
22
22
  from: '../<%= application_name %>'
23
23
  to: './dockerfile/<%= application_name %>'
24
- -
25
- from: './swagger_spec/swagger.yml'
26
- to: './dockerfile/<%= application_name %>/swagger_spec'
27
24
  run:
28
25
  consul_loader:
29
26
  config_file: './consul_keys.yml'
@@ -43,3 +40,15 @@ cucumber:
43
40
  port: 8001
44
41
  path: /v1/health
45
42
  type: bridge
43
+ shell:
44
+ consul_loader:
45
+ config_file: './consul_keys.yml'
46
+ url:
47
+ address: consul
48
+ port: 8500
49
+ type: bridge
50
+ docker:
51
+ application_docker_file: './dockerfile/<%= application_name %>/'
52
+ application_compose_file: './dockercompose/<%= application_name %>/docker-compose-no-server.yml'
53
+ ports:
54
+ - "8001:8001"
@@ -0,0 +1,5 @@
1
+ ---
2
+ <%= application_name %>:
3
+ settings:
4
+ environment: dev
5
+
@@ -1,14 +1,6 @@
1
1
  version: '2'
2
2
 
3
3
  services:
4
- statsd:
5
- image: 'hopsoft/graphite-statsd:latest'
6
- ports:
7
- - "::80"
8
- expose:
9
- - "8125/udp"
10
- environment:
11
- - "SERVICE_8125_NAME=statsd-8125"
12
4
  registrator:
13
5
  image: 'gliderlabs/registrator:latest'
14
6
  command: '-internal -tags=dev consul://consul:8500'
@@ -8,16 +8,7 @@ services:
8
8
  environment:
9
9
  - "CONSUL=consul:8500"
10
10
  links:
11
- - statsd:statsd
12
11
  - syslog:syslog
13
- statsd:
14
- image: 'hopsoft/graphite-statsd:latest'
15
- ports:
16
- - "::80"
17
- expose:
18
- - "8125/udp"
19
- environment:
20
- - "SERVICE_8125_NAME=statsd-8125"
21
12
  registrator:
22
13
  image: 'gliderlabs/registrator:latest'
23
14
  command: '-internal -tags=dev consul://consul:8500'
@@ -5,19 +5,16 @@ EXPOSE 8001
5
5
  # Create directory for server files
6
6
  RUN mkdir /<%= application_name %>
7
7
 
8
- # Add s6 config
9
- ADD s6-etc /etc/s6
10
- RUN chmod -R 755 /etc/s6; \
11
- chmod -R 755 /etc/s6
12
8
 
13
9
  # Add consul template
14
10
  ADD config.ctmpl /<%= application_name %>/config.ctmpl
11
+ ADD entrypoint.sh /entrypoint.sh
15
12
 
16
13
  # Add server files
17
- ADD swagger_spec /swagger
18
14
  ADD <%= application_name %> /<%= application_name %>/<%= application_name %>
19
15
 
20
16
  RUN chmod 755 /<%= application_name %>/<%= application_name %>
17
+ RUN chmod 755 /entrypoint.sh
21
18
 
22
- ENTRYPOINT ["/usr/bin/s6-svscan","/etc/s6"]
19
+ ENTRYPOINT ["/entrypoint.sh"]
23
20
  CMD []
@@ -1,4 +1,3 @@
1
1
  {
2
- "stats_d_server": "{{range service "statsd-8125"}}{{.Address}}:{{.Port}}{{end}}",
3
2
  "syslog_server": "{{range $index, $element := service "syslog-514"}}{{if eq $index 0}}{{.Address}}:{{.Port}}{{end}}{{end}}"
4
3
  }
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ consul-template -consul $CONSUL -exec-reload-signal=SIGTERM -template /<%= application_name %>/config.ctmpl:/<%= application_name %>/config.json -exec "/<%= application_name %>/<%= application_name %> /<%= application_name %>/config.json /"
@@ -0,0 +1,3 @@
1
+ {
2
+ "syslog_server": "syslog_server:514"
3
+ }
@@ -1,16 +1,10 @@
1
1
  package: <%= namespace %>/<%= application_name %>
2
2
  import:
3
- - package: github.com/alexcesaro/statsd
4
- version: ^2.0.0
5
3
  - package: github.com/asaskevich/govalidator
6
4
  version: ^4.0.0
7
- - package: github.com/facebookgo/inject
8
- - package: github.com/gorilla/context
9
- version: ^1.1.0
5
+ - package: github.com/Sirupsen/logrus
10
6
  - package: github.com/gorilla/pat
11
7
  - package: github.com/stretchr/testify
12
8
  version: ^1.1.3
13
9
  subpackages:
14
10
  - mock
15
- testImport:
16
- - package: github.com/alecthomas/assert
@@ -6,14 +6,16 @@ import (
6
6
  "os"
7
7
  )
8
8
 
9
+ // ConfigStruct defines a config object usually created on startup
9
10
  type ConfigStruct struct {
10
- StatsDServerIP string `json:"stats_d_server"`
11
- SysLogIP string `json:"syslog_server"`
12
- RootFolder string
11
+ SysLogIP string `json:"syslog_server"`
12
+ RootFolder string
13
13
  }
14
14
 
15
+ // Config is a global instance of the config
15
16
  var Config ConfigStruct
16
17
 
18
+ // LoadConfig load the config file from the given folder
17
19
  func LoadConfig(config string, rootfolder string) error {
18
20
  fmt.Println("Loading Config: ", config)
19
21
 
@@ -2,38 +2,37 @@ package handlers
2
2
 
3
3
  import (
4
4
  "encoding/json"
5
- "fmt"
6
5
  "net/http"
7
- "log"
8
6
 
9
- "github.com/gorilla/context"
10
- "<%= namespace %>/<%= application_name %>/logging"
7
+ log "github.com/Sirupsen/logrus"
11
8
  )
12
9
 
13
- type EchoDependenciesContainer struct {
14
- StatsD logging.StatsD `inject:"statsd"`
15
- Log *log.Logger `inject:""`
16
- }
10
+ const kTagEcho = "EchoHandler"
17
11
 
18
- var EchoDependencies *EchoDependenciesContainer = &EchoDependenciesContainer{}
19
- const EHTAGNAME = "EchoHandler: "
12
+ type echoHandlerDependencies struct {
13
+ logger *log.Logger
14
+ }
20
15
 
21
- // use the validation middleware to automatically validate input
16
+ // Echo uses the validation middleware to automatically validate input
22
17
  // github.com/asaskevich/govalidator
23
18
  type Echo struct {
24
19
  Echo string `json:"echo" valid:"stringlength(1|255),required"`
25
20
  }
26
21
 
27
- func EchoHandler(rw http.ResponseWriter, r *http.Request) {
28
- EchoDependencies.StatsD.Increment(ECHO_HANDLER + POST + CALLED)
29
- EchoDependencies.Log.Printf("%v Called GET\n", EHTAGNAME)
22
+ type echoHandler struct {
23
+ deps echoHandlerDependencies
24
+ }
25
+
26
+ func (e *echoHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
27
+ e.deps.logger.WithField(kTagEcho, "Called GET")
30
28
 
31
29
  // request is set into the context from the middleware
32
- request := context.Get(r, "request").(*Echo)
33
- fmt.Println("r: ", request)
30
+ request := r.Context().Value(validationRequestKey{}).(Echo)
34
31
 
35
32
  encoder := json.NewEncoder(rw)
36
33
  encoder.Encode(request)
34
+ }
37
35
 
38
- EchoDependencies.StatsD.Increment(ECHO_HANDLER + POST + SUCCESS)
36
+ func newEchoHandler(deps echoHandlerDependencies) http.Handler {
37
+ return &echoHandler{deps}
39
38
  }
@@ -1,74 +1,37 @@
1
1
  package handlers
2
2
 
3
3
  import (
4
+ "context"
4
5
  "encoding/json"
5
- "fmt"
6
6
  "net/http"
7
7
  "net/http/httptest"
8
8
  "testing"
9
- "log"
10
- "os"
11
- "github.com/facebookgo/inject"
12
- "github.com/gorilla/context"
9
+
10
+ log "github.com/Sirupsen/logrus"
13
11
  "github.com/stretchr/testify/assert"
14
- "github.com/stretchr/testify/mock"
15
- "<%= namespace %>/<%= application_name %>/mocks"
16
12
  )
17
13
 
18
- var echoStatsDMock *mocks.MockStatsD
19
-
20
- func echoTestSetup(t *testing.T) {
21
- // create an injection graph containing the mocked elements we wish to replace
22
-
23
- var g inject.Graph
24
-
25
- echoStatsDMock = &mocks.MockStatsD{}
26
- EchoDependencies = &EchoDependenciesContainer{}
27
-
28
- err := g.Provide(
29
- &inject.Object{Value: EchoDependencies},
30
- &inject.Object{Value: echoStatsDMock, Name: "statsd"},
31
- &inject.Object{Value: log.New(os.Stdout, "tester", log.Lshortfile)},
32
- )
33
-
34
- if err != nil {
35
- fmt.Println(err)
36
- }
37
-
38
- if err := g.Populate(); err != nil {
39
- fmt.Println(err)
14
+ func echoTestSetup(t *testing.T) http.Handler {
15
+ deps := echoHandlerDependencies{
16
+ logger: &log.Logger{},
40
17
  }
41
18
 
42
- echoStatsDMock.Mock.On("Increment", mock.Anything).Return()
43
- }
44
-
45
- func TestEchoHandlerSetStats(t *testing.T) {
46
- echoTestSetup(t)
47
-
48
- var responseRecorder httptest.ResponseRecorder
49
- var request http.Request
50
-
51
- echo := Echo{Echo: "Hello World"}
52
- context.Set(&request, "request", &echo)
53
-
54
- EchoHandler(&responseRecorder, &request)
55
-
56
- echoStatsDMock.Mock.AssertCalled(t, "Increment", ECHO_HANDLER+POST+CALLED)
57
- echoStatsDMock.Mock.AssertCalled(t, "Increment", ECHO_HANDLER+POST+SUCCESS)
19
+ return newEchoHandler(deps)
58
20
  }
59
21
 
60
22
  func TestEchoHandlerCorrectlyEchosResponse(t *testing.T) {
61
- echoTestSetup(t)
23
+ h := echoTestSetup(t)
62
24
 
63
25
  var responseRecorder *httptest.ResponseRecorder
64
- var request http.Request
26
+ r := httptest.NewRequest("POST", "/echo", nil)
65
27
 
66
28
  responseRecorder = httptest.NewRecorder()
67
29
 
68
30
  echo := Echo{Echo: "Hello World"}
69
- context.Set(&request, "request", &echo)
31
+ c := context.WithValue(context.Background(), validationRequestKey{}, echo)
32
+ r = r.WithContext(c)
70
33
 
71
- EchoHandler(responseRecorder, &request)
34
+ h.ServeHTTP(responseRecorder, r)
72
35
 
73
36
  body := responseRecorder.Body.Bytes()
74
37
  response := Echo{}
@@ -3,58 +3,34 @@ package handlers
3
3
  import (
4
4
  "encoding/json"
5
5
  "net/http"
6
- "log"
7
6
 
8
- "<%= namespace %>/<%= application_name %>/logging"
7
+ log "github.com/Sirupsen/logrus"
9
8
  )
10
9
 
11
- // This is not particularlly a real world example it mearly shows how a builder or a factory could be injected
12
- // into the HealthHandler
13
- type HealthResponseBuilder struct {
14
- statusMessage string
15
- }
16
-
17
- func (b *HealthResponseBuilder) SetStatusMessage(message string) *HealthResponseBuilder {
18
- b.statusMessage = message
19
- return b
20
- }
10
+ const kTagHealth = "HealthHandler"
21
11
 
22
- func (b *HealthResponseBuilder) Build() HealthResponse {
23
- var hr HealthResponse
24
- hr.StatusMessage = b.statusMessage
25
- return hr
12
+ type HealthResponse struct {
13
+ StatusMessage string `json:"status_message"`
26
14
  }
27
15
 
28
- type HealthDependenciesContainer struct {
29
- // if not specified will create singleton
30
- SingletonBuilder *HealthResponseBuilder `inject:""`
31
-
32
- // statsD interface must use a name type as injection cannot infer ducktypes
33
- Stats logging.StatsD `inject:"statsd"`
34
-
35
- // reference to the log writer
36
- Log *log.Logger `inject:""`
37
-
38
- // if not specified in the graph will automatically create private instance
39
- PrivateBuilder *HealthResponseBuilder `inject:"private"`
16
+ type healthHandlerDependencies struct {
17
+ logger *log.Logger
40
18
  }
41
19
 
42
- type HealthResponse struct {
43
- StatusMessage string `json:"status_message"`
20
+ type healthHandler struct {
21
+ deps healthHandlerDependencies
44
22
  }
45
23
 
46
- var HealthDependencies *HealthDependenciesContainer = &HealthDependenciesContainer{}
47
- const HHTAGNAME = "HealthHandler: "
48
-
49
- func HealthHandler(rw http.ResponseWriter, r *http.Request) {
24
+ func (h *healthHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
50
25
  // all HealthHandlerDependencies are automatically created by injection process
51
- HealthDependencies.Stats.Increment(HEALTH_HANDLER + GET + CALLED)
52
- HealthDependencies.Log.Printf("%v Called GET\n", HHTAGNAME)
26
+ h.deps.logger.WithField(kTagHealth, "Called GET")
53
27
 
54
- response := HealthDependencies.SingletonBuilder.SetStatusMessage("OK").Build()
28
+ response := HealthResponse{StatusMessage: "OK"}
55
29
 
56
30
  encoder := json.NewEncoder(rw)
57
31
  encoder.Encode(&response)
32
+ }
58
33
 
59
- HealthDependencies.Stats.Increment(HEALTH_HANDLER + GET + SUCCESS)
34
+ func newHealthHandler(deps healthHandlerDependencies) http.Handler {
35
+ return &healthHandler{deps}
60
36
  }
@@ -1,65 +1,29 @@
1
1
  package handlers
2
2
 
3
3
  import (
4
- "fmt"
5
4
  "net/http"
6
5
  "net/http/httptest"
7
6
  "testing"
8
- "log"
9
- "os"
10
- "github.com/facebookgo/inject"
11
- "github.com/stretchr/testify/assert"
12
- "github.com/stretchr/testify/mock"
13
- "<%= namespace %>/<%= application_name %>/mocks"
14
- )
15
-
16
- var healthStatsDMock *mocks.MockStatsD
17
-
18
- func healthTestSetup(t *testing.T) {
19
- // create an injection graph containing the mocked elements we wish to replace
20
7
 
21
- var g inject.Graph
8
+ log "github.com/Sirupsen/logrus"
22
9
 
23
- healthStatsDMock = &mocks.MockStatsD{}
24
- HealthDependencies = &HealthDependenciesContainer{}
25
-
26
- err := g.Provide(
27
- &inject.Object{Value: HealthDependencies},
28
- &inject.Object{Value: healthStatsDMock, Name: "statsd"},
29
- &inject.Object{Value: log.New(os.Stdout, "tester", log.Lshortfile)},
30
- )
31
-
32
- if err != nil {
33
- fmt.Println(err)
34
- }
35
-
36
- if err := g.Populate(); err != nil {
37
- fmt.Println(err)
38
- }
10
+ "github.com/stretchr/testify/assert"
11
+ )
39
12
 
40
- healthStatsDMock.Mock.On("Increment", mock.Anything).Return()
13
+ func healthTestSetup(t *testing.T) http.Handler {
14
+ return newHealthHandler(healthHandlerDependencies{
15
+ logger: &log.Logger{},
16
+ })
41
17
  }
42
18
 
43
19
  // Simple test to show how we can use the ResponseRecorder to test our HTTP handlers
44
20
  func TestHealthHandler(t *testing.T) {
45
- healthTestSetup(t)
21
+ handler := healthTestSetup(t)
46
22
 
47
23
  var responseRecorder httptest.ResponseRecorder
48
24
  var request http.Request
49
25
 
50
- HealthHandler(&responseRecorder, &request)
26
+ handler.ServeHTTP(&responseRecorder, &request)
51
27
 
52
28
  assert.Equal(t, 200, responseRecorder.Code)
53
29
  }
54
-
55
- func TestHealthHandlerSetStats(t *testing.T) {
56
- healthTestSetup(t)
57
-
58
- var responseRecorder httptest.ResponseRecorder
59
- var request http.Request
60
-
61
- HealthHandler(&responseRecorder, &request)
62
-
63
- healthStatsDMock.Mock.AssertCalled(t, "Increment", HEALTH_HANDLER+GET+CALLED)
64
- healthStatsDMock.Mock.AssertCalled(t, "Increment", HEALTH_HANDLER+GET+SUCCESS)
65
- }
@@ -2,41 +2,60 @@ package handlers
2
2
 
3
3
  import (
4
4
  "encoding/json"
5
- "fmt"
6
5
  "io/ioutil"
7
6
  "net/http"
8
7
  "reflect"
9
8
 
9
+ log "github.com/Sirupsen/logrus"
10
10
  "github.com/asaskevich/govalidator"
11
11
  "github.com/gorilla/context"
12
- "<%= namespace %>/<%= application_name %>/logging"
13
12
  )
14
13
 
15
- func requestValidationHandler(mainHandlerRef string, t reflect.Type, statsD logging.StatsD, next http.Handler) http.Handler {
16
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
17
-
18
- request := reflect.New(t).Interface()
19
-
20
- defer r.Body.Close()
21
- data, _ := ioutil.ReadAll(r.Body)
22
-
23
- err := json.Unmarshal(data, &request)
24
- if err != nil {
25
- http.Error(w, "Invalid Request", http.StatusBadRequest)
26
- statsD.Increment(mainHandlerRef + BAD_REQUEST)
27
- return
28
- }
29
-
30
- _, err = govalidator.ValidateStruct(request)
31
- if err != nil {
32
- fmt.Println("Validation Error:", err)
33
- http.Error(w, "Invalid Request", http.StatusBadRequest)
34
- statsD.Increment(mainHandlerRef + INVALID_REQUEST)
35
- return
36
- }
37
-
38
- context.Set(r, "request", request)
39
- statsD.Increment(mainHandlerRef + VALID_REQUEST)
40
- next.ServeHTTP(w, r)
41
- })
14
+ const kRequestValidationTag = "RequestValidation"
15
+
16
+ type validationRequestKey struct{}
17
+
18
+ type requestValidationDependencies struct {
19
+ logger *log.Logger
20
+ }
21
+
22
+ type requestValidationHandler struct {
23
+ deps requestValidationDependencies
24
+ t reflect.Type
25
+ next http.Handler
26
+ }
27
+
28
+ func (rv *requestValidationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
29
+ rv.deps.logger.WithField(kRequestValidationTag, r.Method+" Called")
30
+
31
+ request := reflect.New(rv.t).Interface()
32
+
33
+ defer r.Body.Close()
34
+ data, _ := ioutil.ReadAll(r.Body)
35
+
36
+ err := json.Unmarshal(data, &request)
37
+ if err != nil {
38
+ rv.deps.logger.WithField(kRequestValidationTag, "Bad request")
39
+ http.Error(w, "Invalid Request", http.StatusBadRequest)
40
+ return
41
+ }
42
+
43
+ _, err = govalidator.ValidateStruct(request)
44
+ if err != nil {
45
+ rv.deps.logger.WithField(kRequestValidationTag, "Validation error")
46
+ http.Error(w, "Invalid Request", http.StatusBadRequest)
47
+ return
48
+ }
49
+
50
+ context.Set(r, "request", request)
51
+
52
+ rv.next.ServeHTTP(w, r)
53
+ }
54
+
55
+ func newRequestValidationHandler(deps requestValidationDependencies, t reflect.Type, next http.Handler) http.Handler {
56
+ return &requestValidationHandler{
57
+ deps: deps,
58
+ t: t,
59
+ next: next,
60
+ }
42
61
  }
@@ -8,78 +8,71 @@ import (
8
8
  "reflect"
9
9
  "testing"
10
10
 
11
+ log "github.com/Sirupsen/logrus"
11
12
  "github.com/gorilla/context"
12
13
  "github.com/stretchr/testify/assert"
13
14
  "github.com/stretchr/testify/mock"
14
- "<%= namespace %>/<%= application_name %>/mocks"
15
15
  )
16
16
 
17
17
  type mockType struct {
18
18
  FirstName string `json:"first_name" valid:"alphanum,stringlength(1|255),required"`
19
19
  }
20
20
 
21
- var mockHandler *mocks.MockHandler
22
- var mockRequestStatsD *mocks.MockStatsD
21
+ var mh *mockHandler
23
22
 
24
- func setupRequestValidationTests(t *testing.T) {
25
- mockHandler = &mocks.MockHandler{}
26
- mockRequestStatsD = &mocks.MockStatsD{}
23
+ func setupRequestValidationTests(t *testing.T) http.Handler {
24
+ mh = &mockHandler{}
25
+ mh.Mock.On("ServeHTTP", mock.Anything, mock.Anything)
27
26
 
28
- mockRequestStatsD.Mock.On("Increment", mock.Anything)
29
- mockHandler.Mock.On("ServeHTTP", mock.Anything, mock.Anything)
27
+ validationHandler := newRequestValidationHandler(requestValidationDependencies{
28
+ logger: &log.Logger{},
29
+ },
30
+ reflect.TypeOf(mockType{}),
31
+ mh)
32
+
33
+ return validationHandler
30
34
  }
31
35
 
32
36
  func TestCallsNextOnSuccessfulValidation(t *testing.T) {
33
- setupRequestValidationTests(t)
37
+ handler := setupRequestValidationTests(t)
34
38
  var responseRecorder httptest.ResponseRecorder
35
39
  var request http.Request
36
40
  request.Body = ioutil.NopCloser(bytes.NewBufferString(`{"first_name": "Nic"}`))
37
41
 
38
- handlerFunc := requestValidationHandler(HEALTH_HANDLER, reflect.TypeOf(mockType{}), mockRequestStatsD, mockHandler)
39
-
40
- handlerFunc.ServeHTTP(&responseRecorder, &request)
42
+ handler.ServeHTTP(&responseRecorder, &request)
41
43
 
42
- mockHandler.Mock.AssertCalled(t, "ServeHTTP", mock.Anything, mock.Anything)
43
- mockRequestStatsD.Mock.AssertCalled(t, "Increment", HEALTH_HANDLER+VALID_REQUEST)
44
+ mh.Mock.AssertCalled(t, "ServeHTTP", mock.Anything, mock.Anything)
44
45
  }
45
46
 
46
47
  func TestSetsContextSuccessfully(t *testing.T) {
47
- setupRequestValidationTests(t)
48
+ handler := setupRequestValidationTests(t)
48
49
  var responseRecorder httptest.ResponseRecorder
49
50
  var request http.Request
50
51
  request.Body = ioutil.NopCloser(bytes.NewBufferString(`{"first_name": "Nic"}`))
51
52
 
52
- handlerFunc := requestValidationHandler(HEALTH_HANDLER, reflect.TypeOf(mockType{}), mockRequestStatsD, mockHandler)
53
-
54
- handlerFunc.ServeHTTP(&responseRecorder, &request)
53
+ handler.ServeHTTP(&responseRecorder, &request)
55
54
  requestObj := context.Get(&request, "request").(*mockType)
56
55
  assert.Equal(t, "Nic", requestObj.FirstName)
57
56
  }
58
57
 
59
58
  func TestReturnsBadRequestWhenNoObject(t *testing.T) {
60
- setupRequestValidationTests(t)
59
+ handler := setupRequestValidationTests(t)
61
60
  var responseRecorder httptest.ResponseRecorder
62
61
  var request http.Request
63
62
  request.Body = ioutil.NopCloser(bytes.NewBufferString(``))
64
63
 
65
- handlerFunc := requestValidationHandler(HEALTH_HANDLER, reflect.TypeOf(mockType{}), mockRequestStatsD, mockHandler)
66
-
67
- handlerFunc.ServeHTTP(&responseRecorder, &request)
64
+ handler.ServeHTTP(&responseRecorder, &request)
68
65
 
69
66
  assert.Equal(t, http.StatusBadRequest, responseRecorder.Code)
70
- mockRequestStatsD.Mock.AssertCalled(t, "Increment", HEALTH_HANDLER+BAD_REQUEST)
71
67
  }
72
68
 
73
69
  func TestReturnsBadRequestWhenRequestInvalid(t *testing.T) {
74
- setupRequestValidationTests(t)
70
+ handler := setupRequestValidationTests(t)
75
71
  var responseRecorder httptest.ResponseRecorder
76
72
  var request http.Request
77
73
  request.Body = ioutil.NopCloser(bytes.NewBufferString(`{"first_name": ""}`))
78
74
 
79
- handlerFunc := requestValidationHandler(HEALTH_HANDLER, reflect.TypeOf(mockType{}), mockRequestStatsD, mockHandler)
80
-
81
- handlerFunc.ServeHTTP(&responseRecorder, &request)
75
+ handler.ServeHTTP(&responseRecorder, &request)
82
76
 
83
77
  assert.Equal(t, http.StatusBadRequest, responseRecorder.Code)
84
- mockRequestStatsD.Mock.AssertCalled(t, "Increment", HEALTH_HANDLER+INVALID_REQUEST)
85
78
  }
@@ -0,0 +1,12 @@
1
+ package handlers
2
+
3
+ import "net/http"
4
+ import "github.com/stretchr/testify/mock"
5
+
6
+ type mockHandler struct {
7
+ mock.Mock
8
+ }
9
+
10
+ func (m *mockHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
11
+ m.Called(rw, r)
12
+ }
@@ -1,34 +1,24 @@
1
1
  package handlers
2
2
 
3
3
  import (
4
- "net/http"
5
4
  "reflect"
6
5
 
6
+ log "github.com/Sirupsen/logrus"
7
7
  "github.com/gorilla/pat"
8
- "<%= namespace %>/<%= application_name %>/logging"
9
8
  )
10
9
 
11
- type RouterDependenciesContainer struct {
12
- StatsD logging.StatsD `inject:"statsd"`
13
- }
14
-
15
- var RouterDependencies *RouterDependenciesContainer = &RouterDependenciesContainer{}
16
-
17
- func GetRouter() *pat.Router {
10
+ func GetRouter(logger *log.Logger) *pat.Router {
18
11
  r := pat.New()
19
12
 
20
- r.Get("/v1/health", HealthHandler)
21
-
22
- r.Add("POST", "/v1/echo", requestValidationHandler(
23
- ECHO_HANDLER+POST,
13
+ echoHandler := newEchoHandler(echoHandlerDependencies{logger})
14
+ healthHandler := newHealthHandler(healthHandlerDependencies{logger})
15
+ validationHandler := newRequestValidationHandler(
16
+ requestValidationDependencies{logger},
24
17
  reflect.TypeOf(Echo{}),
25
- RouterDependencies.StatsD,
26
- http.HandlerFunc(EchoHandler),
27
- ))
18
+ echoHandler)
28
19
 
29
- //Add routing for static routes
30
- s := http.StripPrefix("/swagger/", http.FileServer(http.Dir("/swagger")))
31
- r.PathPrefix("/swagger/").Handler(s)
20
+ r.Add("GET", "/v1/health", healthHandler)
21
+ r.Add("POST", "/v1/echo", validationHandler)
32
22
 
33
23
  return r
34
24
  }
@@ -2,15 +2,14 @@ package main
2
2
 
3
3
  import (
4
4
  "fmt"
5
+ "log/syslog"
5
6
  "net/http"
6
7
  "os"
7
- "log"
8
- "log/syslog"
8
+
9
+ log "github.com/Sirupsen/logrus"
10
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
9
11
  "<%= namespace %>/<%= application_name %>/global"
10
12
  "<%= namespace %>/<%= application_name %>/handlers"
11
-
12
- "github.com/facebookgo/inject"
13
- "github.com/alexcesaro/statsd"
14
13
  )
15
14
 
16
15
  func main() {
@@ -19,50 +18,20 @@ func main() {
19
18
 
20
19
  global.LoadConfig(config, rootfolder)
21
20
 
22
- setupInjection()
23
21
  setupHandlers()
24
22
  }
25
23
 
26
24
  func setupHandlers() {
27
- http.Handle("/", handlers.GetRouter())
28
-
29
- fmt.Println("Listening for connections on port", 8001)
30
- http.ListenAndServe(fmt.Sprintf(":%v", 8001), nil)
31
- }
32
-
33
- func setupInjection() {
34
- var g inject.Graph
35
-
36
- var err error
37
-
38
- statsdClient, err := statsd.New(statsd.Address(global.Config.StatsDServerIP)) // reference to a statsd client
25
+ logger := log.New()
26
+ hook, err := logrus_syslog.NewSyslogHook("udp", global.Config.SysLogIP, syslog.LOG_DEBUG, "")
39
27
  if err != nil {
40
- panic(fmt.Sprintln("Unable to create StatsD Client: ", err))
28
+ log.Fatal("Unable to create sylogger")
41
29
  }
42
30
 
43
- syslogWriter, err := syslog.Dial("udp", global.Config.SysLogIP, syslog.LOG_SYSLOG, "sorcery")
44
- if err != nil {
45
- panic(fmt.Sprintln("Unable to connect to syslog: ", err))
46
- }
47
-
48
- logWriter := log.New(syslogWriter, "<%= application_name %>: ", log.Lshortfile)
49
-
50
- err = g.Provide(
51
- &inject.Object{Value: handlers.RouterDependencies},
52
- &inject.Object{Value: handlers.HealthDependencies},
53
- &inject.Object{Value: handlers.EchoDependencies},
54
- &inject.Object{Value: statsdClient, Name: "statsd"},
55
- &inject.Object{Value: logWriter},
56
- )
31
+ logger.Hooks.Add(hook)
57
32
 
58
- if err != nil {
59
- fmt.Println(err)
60
- }
33
+ http.Handle("/", handlers.GetRouter(logger))
61
34
 
62
- // Here the Populate call is creating instances of NameAPI &
63
- // PlanetAPI, and setting the HTTPTransport on both to the
64
- // http.DefaultTransport provided above:
65
- if err := g.Populate(); err != nil {
66
- fmt.Println(err)
67
- }
35
+ fmt.Println("Listening for connections on port", 8001)
36
+ http.ListenAndServe(fmt.Sprintf(":%v", 8001), nil)
68
37
  }
@@ -1,7 +1,7 @@
1
1
  module Minke
2
2
  module Generators
3
3
  module GoMicroservice
4
- VERSION = "0.8.7"
4
+ VERSION = "0.9.1"
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minke-generator-go
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.7
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nic Jackson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-05 00:00:00.000000000 Z
11
+ date: 2017-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -75,40 +75,33 @@ files:
75
75
  - bin/setup
76
76
  - lib/generators/gomicroservice.rb
77
77
  - lib/generators/gomicroservice/scaffold/.gitignore.erb
78
- - lib/generators/gomicroservice/scaffold/_build/.gitignore
79
- - lib/generators/gomicroservice/scaffold/_build/Gemfile
80
- - lib/generators/gomicroservice/scaffold/_build/Rakefile
81
- - lib/generators/gomicroservice/scaffold/_build/config.yml.erb
82
- - lib/generators/gomicroservice/scaffold/_build/consul_keys.yml.erb
83
- - lib/generators/gomicroservice/scaffold/_build/dockercompose/<%= application_name
78
+ - lib/generators/gomicroservice/scaffold/Makefile.erb
79
+ - lib/generators/gomicroservice/scaffold/_minke/.gitignore
80
+ - lib/generators/gomicroservice/scaffold/_minke/Gemfile
81
+ - lib/generators/gomicroservice/scaffold/_minke/config.yml.erb
82
+ - lib/generators/gomicroservice/scaffold/_minke/consul_keys.yml.erb
83
+ - lib/generators/gomicroservice/scaffold/_minke/dockercompose/<%= application_name
84
+ %>/docker-compose-no-server.yml.erb
85
+ - lib/generators/gomicroservice/scaffold/_minke/dockercompose/<%= application_name
84
86
  %>/docker-compose.yml.erb
85
- - lib/generators/gomicroservice/scaffold/_build/dockercompose/<%= application_name
86
- %>/docker-no-server.yml.erb
87
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/Dockerfile.erb
88
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/config.ctmpl.erb
89
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/.s6-svscan/crash
90
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/.s6-svscan/finish
91
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/app/finish
92
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/app/run.erb
93
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/consul-template/finish
94
- - lib/generators/gomicroservice/scaffold/_build/dockerfile/<%= application_name %>/s6-etc/consul-template/run.erb
95
- - lib/generators/gomicroservice/scaffold/_build/features/health.feature
96
- - lib/generators/gomicroservice/scaffold/_build/features/steps/http.rb
97
- - lib/generators/gomicroservice/scaffold/_build/features/support/env.rb.erb
98
- - lib/generators/gomicroservice/scaffold/_build/swagger_spec/swagger.yml.erb
87
+ - lib/generators/gomicroservice/scaffold/_minke/dockerfile/<%= application_name %>/Dockerfile.erb
88
+ - lib/generators/gomicroservice/scaffold/_minke/dockerfile/<%= application_name %>/config.ctmpl.erb
89
+ - lib/generators/gomicroservice/scaffold/_minke/dockerfile/<%= application_name %>/entrypoint.sh.erb
90
+ - lib/generators/gomicroservice/scaffold/_minke/features/health.feature
91
+ - lib/generators/gomicroservice/scaffold/_minke/features/steps/http.rb
92
+ - lib/generators/gomicroservice/scaffold/_minke/features/support/env.rb.erb
93
+ - lib/generators/gomicroservice/scaffold/config.json
99
94
  - lib/generators/gomicroservice/scaffold/glide.yaml.erb
100
95
  - lib/generators/gomicroservice/scaffold/global/global.go
101
- - lib/generators/gomicroservice/scaffold/handlers/const.go.erb
102
96
  - lib/generators/gomicroservice/scaffold/handlers/echo.go.erb
103
97
  - lib/generators/gomicroservice/scaffold/handlers/echo_test.go.erb
104
98
  - lib/generators/gomicroservice/scaffold/handlers/health.go.erb
105
99
  - lib/generators/gomicroservice/scaffold/handlers/health_test.go.erb
106
100
  - lib/generators/gomicroservice/scaffold/handlers/middleware_requestvalidation.go.erb
107
101
  - lib/generators/gomicroservice/scaffold/handlers/middleware_requestvalidation_test.go.erb
102
+ - lib/generators/gomicroservice/scaffold/handlers/mockHandler.go.erb
108
103
  - lib/generators/gomicroservice/scaffold/handlers/xx_router.go.erb
109
- - lib/generators/gomicroservice/scaffold/logging/StatsD.go
110
104
  - lib/generators/gomicroservice/scaffold/main.go.erb
111
- - lib/generators/gomicroservice/scaffold/mocks/mocks.go
112
105
  - lib/generators/gomicroservice/version.rb
113
106
  - minke-generator-go.gemspec
114
107
  homepage: https://github.com/nicholasjackson/minkie-generator-go
@@ -132,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
125
  version: '0'
133
126
  requirements: []
134
127
  rubyforge_project:
135
- rubygems_version: 2.4.5
128
+ rubygems_version: 2.6.10
136
129
  signing_key:
137
130
  specification_version: 4
138
131
  summary: Go microservice template for Minke
@@ -1,4 +0,0 @@
1
- require 'minke'
2
-
3
- spec = Gem::Specification.find_by_name 'minke'
4
- Rake.add_rakelib "#{spec.gem_dir}/lib/minke/rake"
@@ -1,13 +0,0 @@
1
- ---
2
- <%= application_name %>:
3
- Credentials:
4
- mysql:
5
- username: root
6
- password: my-secret-pw
7
- Settings:
8
- environment: dev
9
- mysql:
10
- db_name: <%= application_name %>
11
- statsd:
12
- host: statsd
13
- port: 8125
@@ -1,3 +0,0 @@
1
- #!/bin/sh
2
-
3
- exec /<%= application_name %>/<%= application_name %> /<%= application_name %>/config.json /<%= application_name %>
@@ -1,3 +0,0 @@
1
- #!/bin/sh
2
-
3
- exec /usr/bin/consul-template -consul=$CONSUL -template "/<%= application_name %>/config.ctmpl:/<%= application_name %>/config.json:killall <%= application_name %>"
@@ -1,34 +0,0 @@
1
- swagger: '2.0'
2
- info:
3
- title: <%= application_name %>
4
- description: <%= application_name %> Description
5
- version: 1.0.0
6
- host: api.test.com
7
- schemes:
8
- - http
9
- basePath: /v1
10
- produces:
11
- - application/json
12
- paths:
13
- /health:
14
- get:
15
- summary: Health Check
16
- description: |
17
- The Health Check endpoint is used to determine the current status for the health of the api.
18
- This endpoint will be used by other systems such as Consul and other service discovery systems.
19
- tags:
20
- - Health
21
- responses:
22
- '200':
23
- description: Status message from server describing current health
24
- schema:
25
- type: array
26
- items:
27
- $ref: '#/definitions/HealthResponse'
28
- definitions:
29
- HealthResponse:
30
- type: object
31
- properties:
32
- status_message:
33
- type: string
34
- description: 'Plain text readable response corresponding to current health status'
@@ -1,12 +0,0 @@
1
- package handlers
2
-
3
- const GET = ".get"
4
- const POST = ".post"
5
- const CALLED = ".called"
6
- const SUCCESS = ".success"
7
- const BAD_REQUEST = ".bad_request"
8
- const INVALID_REQUEST = ".invalid_request"
9
- const VALID_REQUEST = ".valid_request"
10
-
11
- const HEALTH_HANDLER = "<%= application_name %>.health_handler"
12
- const ECHO_HANDLER = "<%= application_name %>.echo_handler"
@@ -1,6 +0,0 @@
1
- package logging
2
-
3
- // StatsD interface is to allow the class .. to be injected as a DuckType
4
- type StatsD interface {
5
- Increment(string)
6
- }
@@ -1,23 +0,0 @@
1
- package mocks
2
-
3
- import (
4
- "net/http"
5
-
6
- "github.com/stretchr/testify/mock"
7
- )
8
-
9
- type MockStatsD struct {
10
- mock.Mock
11
- }
12
-
13
- func (m *MockStatsD) Increment(label string) {
14
- _ = m.Mock.Called(label)
15
- }
16
-
17
- type MockHandler struct {
18
- mock.Mock
19
- }
20
-
21
- func (m *MockHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
22
- _ = m.Mock.Called(w, r)
23
- }