refactor(errors): new error "helpers", following a more golang way
This commit is contained in:
20
internals/router/errors/400.go
Normal file
20
internals/router/errors/400.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ErrMissingParams struct {
|
||||
defaultErr
|
||||
Params []string `json:"params"`
|
||||
}
|
||||
|
||||
func NewErrMissingParams(params ...string) ErrMissingParams {
|
||||
return ErrMissingParams{Params: params}
|
||||
}
|
||||
func (e ErrMissingParams) Error() string {
|
||||
return fmt.Sprintf("Missing parameters: %s.", strings.Join(e.Params, ", "))
|
||||
}
|
||||
func (e ErrMissingParams) Status() int { return http.StatusBadRequest }
|
||||
15
internals/router/errors/500.go
Normal file
15
internals/router/errors/500.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ErrInternal struct {
|
||||
defaultErr
|
||||
Err string `json:"error"`
|
||||
}
|
||||
|
||||
func NewErrInternal(err ...error) ErrInternal { return ErrInternal{Err: errors.Join(err...).Error()} }
|
||||
func (e ErrInternal) Error() string { return e.Err }
|
||||
func (e ErrInternal) Status() int { return http.StatusInternalServerError }
|
||||
90
internals/router/errors/errors.templ
Normal file
90
internals/router/errors/errors.templ
Normal file
@@ -0,0 +1,90 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"extrovert/templates/layouts"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Error interface {
|
||||
Error() string
|
||||
Status() int
|
||||
ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
Component() templ.Component
|
||||
JSON() string
|
||||
}
|
||||
|
||||
type defaultErr struct{}
|
||||
|
||||
func (e defaultErr) Error() string {
|
||||
return "Error: This method should have been overridden :')"
|
||||
}
|
||||
|
||||
func (e defaultErr) Status() int {
|
||||
return http.StatusNotImplemented
|
||||
}
|
||||
|
||||
func (e defaultErr) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.Contains(r.Header.Get("Accept"), "text/html") {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
|
||||
err := e.Component().Render(r.Context(), w)
|
||||
if err != nil {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte("Unable to render error message, using JSON representation: " + e.JSON()))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
_, err := w.Write([]byte(e.JSON()))
|
||||
if err != nil {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte("Unable to send error information due to: " + err.Error()))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
w.WriteHeader(e.Status())
|
||||
}
|
||||
|
||||
func (e defaultErr) JSON() string {
|
||||
type jsonErr struct {
|
||||
Error string `json:"error"`
|
||||
Info any `json:"info"`
|
||||
}
|
||||
js, err := json.Marshal(jsonErr{
|
||||
Error: e.Error(),
|
||||
Info: e,
|
||||
})
|
||||
if err != nil {
|
||||
js, _ = json.Marshal(jsonErr{
|
||||
Error: "Unable to parse JSON of error",
|
||||
Info: err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return string(js)
|
||||
}
|
||||
|
||||
templ (e defaultErr) Component() {
|
||||
@layouts.Page("Error") {
|
||||
<dialog open>
|
||||
<article>
|
||||
<header>
|
||||
<p>Error</p>
|
||||
</header>
|
||||
<p>
|
||||
{ e.Error() }
|
||||
</p>
|
||||
<footer>
|
||||
<a href={ templ.SafeURL("/") }>
|
||||
<button>Return to homepage</button>
|
||||
</a>
|
||||
</footer>
|
||||
</article>
|
||||
</dialog>
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,18 @@ import (
|
||||
"extrovert/templates/layouts"
|
||||
"extrovert/components"
|
||||
"net/http"
|
||||
"extrovert/internals/router/errors"
|
||||
e "errors"
|
||||
)
|
||||
|
||||
type Homepage struct{}
|
||||
|
||||
func (h Homepage) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_ = h.page().Render(context.Background(), w)
|
||||
err := h.page().Render(context.Background(), w)
|
||||
if err != nil {
|
||||
errors.NewErrInternal(e.New("Unable to render dashboard"), err).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
templ (h Homepage) page() {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
e "errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"extrovert/internals"
|
||||
"extrovert/internals/router/errors"
|
||||
)
|
||||
|
||||
type AITxt struct{}
|
||||
@@ -13,23 +14,24 @@ func (_ AITxt) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Cache-Control", "max-age=604800, stale-while-revalidate=86400, stale-if-error=86400")
|
||||
w.Header().Add("CDN-Cache-Control", "max-age=604800")
|
||||
|
||||
error := internals.HttpErrorHelper(w)
|
||||
|
||||
aiList, err := http.Get("https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/ai.txt")
|
||||
if error("Error trying to create ai block list", err, http.StatusInternalServerError) {
|
||||
list, err := http.Get("https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/ai.txt")
|
||||
if err != nil {
|
||||
errors.NewErrInternal(e.New("Unable to fetch ai.txt list"), err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
bytes, err := io.ReadAll(aiList.Body)
|
||||
if error("Error trying to create ai block list", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
_, err = io.WriteString(w, string(bytes))
|
||||
if error("Error trying to create ai block list", err, http.StatusInternalServerError) {
|
||||
bytes, err := io.ReadAll(list.Body)
|
||||
if err != nil {
|
||||
errors.NewErrInternal(e.New("Unable to read dynamic ai.txt list"), err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Add("Content-Type", "text/plain")
|
||||
_, err = w.Write(bytes)
|
||||
if err != nil {
|
||||
errors.NewErrInternal(e.New("Unable to write ai.txt list"), err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type RobotsTxt struct{}
|
||||
@@ -38,19 +40,21 @@ func (_ RobotsTxt) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Cache-Control", "max-age=604800, stale-while-revalidate=86400, stale-if-error=86400")
|
||||
w.Header().Add("CDN-Cache-Control", "max-age=604800")
|
||||
|
||||
error := internals.HttpErrorHelper(w)
|
||||
aiList, err := http.Get("https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/robots.txt")
|
||||
if error("Error trying to create robots block list", err, http.StatusInternalServerError) {
|
||||
list, err := http.Get("https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/robots.txt")
|
||||
if err != nil {
|
||||
errors.NewErrInternal(e.New("Unable to fetch robots.txt list"), err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
bytes, err := io.ReadAll(aiList.Body)
|
||||
if error("Error trying to create robots block list", err, http.StatusInternalServerError) {
|
||||
bytes, err := io.ReadAll(list.Body)
|
||||
if err != nil {
|
||||
errors.NewErrInternal(e.New("Unable to read dynamic robots.txt list"), err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = io.WriteString(w, string(bytes))
|
||||
if error("Error trying to create robots block list", err, http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
errors.NewErrInternal(e.New("Unable to write robots.txt list"), err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Add("Content-Type", "text/plain")
|
||||
|
||||
Reference in New Issue
Block a user