Commit 648a15c
Changed files (3)
cmd
web
docs
cmd/web/handlers.go
@@ -14,9 +14,18 @@ type PageData struct {
Content interface{}
}
+// config holds all the configuration settings for the application
+type config struct {
+ port int
+ env string
+ staticDir string
+ htmlDir string
+}
+
// application holds the application-wide dependencies and configuration
// This demonstrates a custom handler type that can hold state and dependencies
type application struct {
+ config config
logger *log.Logger
serviceName string
}
@@ -34,10 +43,10 @@ type TemplateHandler struct {
func (th *TemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Server", th.app.serviceName)
- // Parse templates with inheritance
+ // Parse templates with inheritance using configurable paths
ts, err := template.ParseFiles(
- "./ui/html/layouts/base.tmpl",
- "./ui/html/pages/"+th.templateName,
+ th.app.config.htmlDir+"/layouts/base.tmpl",
+ th.app.config.htmlDir+"/pages/"+th.templateName,
)
if err != nil {
th.app.logger.Println(err.Error())
@@ -66,10 +75,10 @@ func (th *TemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (app *application) home(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Server", app.serviceName)
- // Parse templates with inheritance
+ // Parse templates with inheritance using configurable paths
ts, err := template.ParseFiles(
- "./ui/html/layouts/base.tmpl",
- "./ui/html/pages/home.tmpl",
+ app.config.htmlDir+"/layouts/base.tmpl",
+ app.config.htmlDir+"/pages/home.tmpl",
)
if err != nil {
app.logger.Println(err.Error())
@@ -100,10 +109,10 @@ func (app *application) home(w http.ResponseWriter, r *http.Request) {
func (app *application) processSubmit(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Server", app.serviceName)
- // Parse templates with inheritance
+ // Parse templates with inheritance using configurable paths
ts, err := template.ParseFiles(
- "./ui/html/layouts/base.tmpl",
- "./ui/html/pages/complete.tmpl",
+ app.config.htmlDir+"/layouts/base.tmpl",
+ app.config.htmlDir+"/pages/complete.tmpl",
)
if err != nil {
app.logger.Println(err.Error())
cmd/web/main.go
@@ -1,14 +1,44 @@
package main
import (
+ "flag"
"log"
"net/http"
+ "os"
+ "strconv"
)
func main() {
+ // Declare an instance of the config struct to hold configuration settings
+ var cfg config
+
+ // Parse command-line flags with sensible defaults
+ flag.IntVar(&cfg.port, "port", 4000, "HTTP server port")
+ flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)")
+ flag.StringVar(&cfg.staticDir, "static-dir", "./ui/static", "Path to static assets")
+ flag.StringVar(&cfg.htmlDir, "html-dir", "./ui/html", "Path to HTML templates")
+ flag.Parse()
+
+ // Check for environment variable overrides
+ if envPort := os.Getenv("PORT"); envPort != "" {
+ if port, err := strconv.Atoi(envPort); err == nil {
+ cfg.port = port
+ }
+ }
+ if envEnv := os.Getenv("ENV"); envEnv != "" {
+ cfg.env = envEnv
+ }
+ if envStaticDir := os.Getenv("STATIC_DIR"); envStaticDir != "" {
+ cfg.staticDir = envStaticDir
+ }
+ if envHtmlDir := os.Getenv("HTML_DIR"); envHtmlDir != "" {
+ cfg.htmlDir = envHtmlDir
+ }
+
// Create an instance of the application struct, containing the application-wide
// dependencies and configuration settings.
app := &application{
+ config: cfg,
logger: log.New(log.Writer(), "", log.LstdFlags),
serviceName: "buylater.email",
}
@@ -17,10 +47,10 @@ func main() {
// URL patterns and their corresponding handlers.
mux := http.NewServeMux()
- // Create a file server which serves files out of the "./ui/static" directory.
+ // Create a file server which serves files out of the configured static directory.
// Note that the path given to the http.Dir function is relative to the project
// directory root.
- fileServer := http.FileServer(http.Dir("./ui/static/"))
+ fileServer := http.FileServer(http.Dir(app.config.staticDir))
// Use the mux.Handle() function to register the file server as the handler for
// all URL paths that start with "/static/". For matching paths, we strip the
@@ -55,10 +85,10 @@ func main() {
})
// Print a log message to indicate the server is starting.
- app.logger.Printf("Starting server on http://localhost:4000")
+ app.logger.Printf("Starting server on http://localhost:%d in %s mode", app.config.port, app.config.env)
- // Start the web server on port 4000. If ListenAndServe returns an error
+ // Start the web server on the configured port. If ListenAndServe returns an error
// we use log.Fatal() to log the error and terminate the program.
- err := http.ListenAndServe(":4000", mux)
+ err := http.ListenAndServe(":"+strconv.Itoa(app.config.port), mux)
log.Fatal(err)
}
docs/project_plan.md
@@ -18,7 +18,7 @@ Phase 1 lays the groundwork by methodically working through the Let's Go book, c
| 1.8 | HTML Templating and Inheritance | Completed | Medium | 2.8 | [task_1.8.md](todo/task_1.8.md) |
| 1.9 | Serving Static Files | Completed | Small | 2.9 | [task_1.9.md](todo/task_1.9.md) |
| 1.10 | The HTTP Handler Interface | Completed | Medium | 2.10 | [task_1.10.md](todo/task_1.10.md) |
-| 1.11 | Managing Configuration Settings | Pending | Medium | 3.1 | [task_1.11.md](todo/task_1.11.md) |
+| 1.11 | Managing Configuration Settings | Completed | Medium | 3.1 | [task_1.11.md](todo/task_1.11.md) |
| 1.12 | Structured Logging | Pending | Medium | 3.2 | [task_1.12.md](todo/task_1.12.md) |
| 1.13 | Dependency Injection | Pending | Medium | 3.3 | [task_1.13.md](todo/task_1.13.md) |
| 1.14 | Centralized Error Handling | Pending | Medium | 3.4 | [task_1.14.md](todo/task_1.14.md) |