minke-generator-go 0.8.7 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- }