/
app.go
134 lines (113 loc) · 4.32 KB
/
app.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
package main
import (
"net"
"net/http"
"os"
fthealth "github.com/Financial-Times/go-fthealth/v1_1"
logger "github.com/Financial-Times/go-logger"
"github.com/Financial-Times/http-handlers-go/httphandlers"
"github.com/Financial-Times/public-organisations-api/v3/organisations"
status "github.com/Financial-Times/service-status-go/httphandlers"
"fmt"
"strconv"
"time"
"github.com/gorilla/mux"
cli "github.com/jawher/mow.cli"
metrics "github.com/rcrowley/go-metrics"
log "github.com/sirupsen/logrus"
)
var httpClient = http.Client{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 15 * time.Second,
}).DialContext,
MaxIdleConnsPerHost: 128,
IdleConnTimeout: 60 * time.Second,
},
}
func main() {
app := cli.App("public-organisations-api", "A public RESTful API for accessing organisations in Neo4j")
appSystemCode := app.String(cli.StringOpt{
Name: "app-system-code",
Value: "public-organisation-api",
Desc: "System Code of the application",
EnvVar: "APP_SYSTEM_CODE",
})
port := app.String(cli.StringOpt{
Name: "port",
Value: "8080",
Desc: "Port to listen on",
EnvVar: "APP_PORT",
})
logLevel := app.String(cli.StringOpt{
Name: "log-level",
Value: "INFO",
Desc: "Log level to use",
EnvVar: "LOG_LEVEL",
})
env := app.String(cli.StringOpt{
Name: "env",
Value: "local",
Desc: "environment this app is running in",
})
cacheDuration := app.String(cli.StringOpt{
Name: "cache-duration",
Value: "30s",
Desc: "Duration Get requests should be cached for. e.g. 2h45m would set the max-age value to '7440' seconds",
EnvVar: "CACHE_DURATION",
})
publicConceptsApiURL := app.String(cli.StringOpt{
Name: "publicConceptsApiURL",
Value: "http://localhost:8081",
Desc: "Public concepts API endpoint URL.",
EnvVar: "CONCEPTS_API",
})
logger.InitLogger(*appSystemCode, *logLevel)
logger.Infof("[Startup] public-organisations-api is starting ")
app.Action = func() {
log.Infof("public-organisations-api will listen on port: %s", *port)
runServer(*port, *cacheDuration, *env, *publicConceptsApiURL)
}
log.SetFormatter(&log.TextFormatter{DisableColors: true})
log.SetLevel(log.InfoLevel)
log.Infof("Application started with args %s", os.Args)
app.Run(os.Args)
}
func runServer(port string, cacheDuration string, env string, publicConceptsApiURL string) {
if duration, durationErr := time.ParseDuration(cacheDuration); durationErr != nil {
log.Fatalf("Failed to parse cache duration string, %v", durationErr)
} else {
organisations.CacheControlHeader = fmt.Sprintf("max-age=%s, public", strconv.FormatFloat(duration.Seconds(), 'f', 0, 64))
}
servicesRouter := mux.NewRouter()
handler := organisations.NewHandler(&httpClient, publicConceptsApiURL)
// Healthchecks and standards first
healthCheck := fthealth.TimedHealthCheck{
HealthCheck: fthealth.HealthCheck{
SystemCode: "public-org-api",
Name: "PublicOrganisationsRead Healthcheck",
Description: "Checks for the downstream services' health",
Checks: []fthealth.Check{handler.HealthCheck()},
},
Timeout: 10 * time.Second,
}
servicesRouter.HandleFunc("/__health", fthealth.Handler(healthCheck))
// Then API specific ones:
handler.RegisterHandlers(servicesRouter)
var monitoringRouter http.Handler = servicesRouter
monitoringRouter = httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), monitoringRouter)
monitoringRouter = httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry, monitoringRouter)
// The following endpoints should not be monitored or logged (varnish calls one of these every second, depending on config)
// The top one of these build info endpoints feels more correct, but the lower one matches what we have in Dropwizard,
// so it's what apps expect currently same as ping, the content of build-info needs more definition
//using http router here to be able to catch "/"
http.HandleFunc(status.PingPath, status.PingHandler)
http.HandleFunc(status.PingPathDW, status.PingHandler)
http.HandleFunc(status.BuildInfoPath, status.BuildInfoHandler)
http.HandleFunc(status.BuildInfoPathDW, status.BuildInfoHandler)
servicesRouter.HandleFunc(status.GTGPath, status.NewGoodToGoHandler(handler.GTG))
http.Handle("/", monitoringRouter)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatalf("Unable to start server: %v", err)
}
}