Commit 3998ae5
Changed files (4)
cmd/web/handlers.go
@@ -74,8 +74,7 @@ func (th *TemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
th.app.config.htmlDir+"/pages/"+th.templateName,
)
if err != nil {
- th.app.logger.error.Println(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ th.app.serverError(w, err)
return
}
@@ -89,8 +88,7 @@ func (th *TemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Execute template
err = ts.ExecuteTemplate(w, "base", data)
if err != nil {
- th.app.logger.error.Println(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ th.app.serverError(w, err)
}
}
@@ -106,8 +104,7 @@ func (app *application) home(w http.ResponseWriter, r *http.Request) {
app.config.htmlDir+"/pages/home.tmpl",
)
if err != nil {
- app.logger.error.Println(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ app.serverError(w, err)
return
}
@@ -121,8 +118,7 @@ func (app *application) home(w http.ResponseWriter, r *http.Request) {
// Execute template
err = ts.ExecuteTemplate(w, "base", data)
if err != nil {
- app.logger.error.Println(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ app.serverError(w, err)
}
}
@@ -140,8 +136,7 @@ func (app *application) processSubmit(w http.ResponseWriter, r *http.Request) {
app.config.htmlDir+"/pages/complete.tmpl",
)
if err != nil {
- app.logger.error.Println(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ app.serverError(w, err)
return
}
@@ -155,8 +150,7 @@ func (app *application) processSubmit(w http.ResponseWriter, r *http.Request) {
// Execute template
err = ts.ExecuteTemplate(w, "base", data)
if err != nil {
- app.logger.error.Println(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ app.serverError(w, err)
}
}
@@ -166,9 +160,8 @@ func (app *application) confirmWithToken(w http.ResponseWriter, r *http.Request)
token := r.PathValue("token")
if !isValidToken(token) {
- w.Header().Add("Server", app.serviceName)
app.logger.error.Printf("Invalid token attempted: %s", token)
- http.NotFound(w, r)
+ app.notFound(w)
return
}
docs/project_plan.md
@@ -21,7 +21,7 @@ Phase 1 lays the groundwork by methodically working through the Let's Go book, c
| 1.11 | Managing Configuration Settings | Completed | Medium | 3.1 | [task_1.11.md](todo/task_1.11.md) |
| 1.12 | Structured Logging | Completed | Medium | 3.2 | [task_1.12.md](todo/task_1.12.md) |
| 1.13 | Dependency Injection | Completed | 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) |
+| 1.14 | Centralized Error Handling | Completed | Medium | 3.4 | [task_1.14.md](todo/task_1.14.md) |
| 1.15 | Isolating the Application Routes | Pending | Small | 3.5 | [task_1.15.md](todo/task_1.15.md) |
## Status Legend
ui/html/pages/error.tmpl
@@ -0,0 +1,124 @@
+{{define "title"}}{{.Title}} - {{.ServiceName}}{{end}}
+
+{{define "main"}}
+<div class="error-page">
+ <div class="error-content">
+ <div class="error-code">{{.Content.ErrorCode}}</div>
+ <h1 class="error-title">{{.Content.ErrorTitle}}</h1>
+ <p class="error-message">{{.Content.ErrorMessage}}</p>
+
+ <div class="error-actions">
+ <a href="/" class="cta-button">Go Home</a>
+ <a href="/submit" class="cta-button secondary">Schedule Reminder</a>
+ </div>
+
+ <div class="error-help">
+ <p>If you continue to experience problems, please check:</p>
+ <ul>
+ <li>The URL is typed correctly</li>
+ <li>The page you're looking for still exists</li>
+ <li>Your internet connection is working</li>
+ </ul>
+ </div>
+ </div>
+</div>
+
+<style>
+.error-page {
+ text-align: center;
+ padding: 4rem 0;
+ min-height: 60vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.error-content {
+ max-width: 600px;
+ margin: 0 auto;
+}
+
+.error-code {
+ font-size: 8rem;
+ font-weight: bold;
+ color: #e74c3c;
+ line-height: 1;
+ margin-bottom: 1rem;
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
+}
+
+.error-title {
+ font-size: 2.5rem;
+ margin-bottom: 1rem;
+ color: #2c3e50;
+}
+
+.error-message {
+ font-size: 1.2rem;
+ margin-bottom: 2rem;
+ color: #7f8c8d;
+ line-height: 1.6;
+}
+
+.error-actions {
+ margin: 2rem 0;
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+.error-actions .cta-button.secondary {
+ background: transparent;
+ color: #e74c3c;
+ border: 2px solid #e74c3c;
+}
+
+.error-actions .cta-button.secondary:hover {
+ background: #e74c3c;
+ color: white;
+}
+
+.error-help {
+ margin-top: 3rem;
+ padding: 2rem;
+ background: #f8f9fa;
+ border-radius: 8px;
+ text-align: left;
+}
+
+.error-help h3 {
+ margin-bottom: 1rem;
+ color: #2c3e50;
+}
+
+.error-help ul {
+ margin: 1rem 0;
+ padding-left: 1.5rem;
+}
+
+.error-help li {
+ margin-bottom: 0.5rem;
+ color: #7f8c8d;
+}
+
+@media (max-width: 768px) {
+ .error-code {
+ font-size: 6rem;
+ }
+
+ .error-title {
+ font-size: 2rem;
+ }
+
+ .error-actions {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .error-actions .cta-button {
+ width: 200px;
+ }
+}
+</style>
+{{end}}
\ No newline at end of file
buylater.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Buylater Email Service
+After=network.target
+
+[Service]
+Type=simple
+ExecStart=/home/crash/git/buylater/bin/buylater -port=3003
+WorkingDirectory=/home/crash/git/buylater
+Restart=always
+RestartSec=5
+
+[Install]
+WantedBy=default.target
\ No newline at end of file