feat: add an ID for every request

- Add a middleware to add an ID for every request for the purpose of
  cross referencing requests and errors.
- Add functions for handling client and server errors.
This commit is contained in:
Dan Anglin 2024-10-17 18:25:43 +01:00
parent 78cbc1bac5
commit 9cb1f8ed4b
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
2 changed files with 56 additions and 12 deletions

View file

@ -2,21 +2,45 @@ package server
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
)
func sendJSONResponse(w http.ResponseWriter, statusCode int, payload any) {
func sendResponse(writer http.ResponseWriter, statusCode int, payload any) {
data, err := json.Marshal(payload)
if err != nil {
slog.Error("Error marshalling the response to JSON", "error", err.Error())
w.WriteHeader(http.StatusInternalServerError)
sendServerError(
writer,
fmt.Errorf("error marshalling the JSON response: %w", err),
)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
_, _ = w.Write(data)
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(statusCode)
_, _ = writer.Write(data)
}
func sendClientError(writer http.ResponseWriter, statusCode int, err error) {
sendErrorResponse(
writer,
statusCode,
"Client Error: "+err.Error(),
)
}
func sendServerError(writer http.ResponseWriter, err error) {
sendErrorResponse(
writer,
http.StatusInternalServerError,
"Server Error: "+err.Error(),
)
}
func sendErrorResponse(writer http.ResponseWriter, statusCode int, message string) {
slog.Error(message, "request-id", writer.Header().Get("X-Request-ID"))
http.Error(writer, http.StatusText(statusCode), statusCode)
}

View file

@ -1,7 +1,10 @@
package server
import (
"crypto/rand"
"encoding/hex"
"fmt"
"log/slog"
"net/http"
"codeflow.dananglin.me.uk/apollo/indieauth-server/internal/config"
@ -10,13 +13,30 @@ import (
func newMux(cfg config.Config) *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("GET /.well-known/oauth-authorization-server", metadataHandleFunc(cfg.Domain))
mux.Handle("GET /.well-known/oauth-authorization-server", setRequestID(metadataHandler(cfg.Domain)))
return mux
}
func metadataHandleFunc(domain string) http.HandlerFunc {
return func(writer http.ResponseWriter, _ *http.Request) {
func setRequestID(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
requestID := "UNKNOWN"
id := make([]byte, 16)
if _, err := rand.Read(id); err != nil {
slog.Error("unable to create the request ID.", "error", err.Error())
} else {
requestID = hex.EncodeToString(id)
}
writer.Header().Set("X-Request-ID", requestID)
next.ServeHTTP(writer, request)
})
}
func metadataHandler(domain string) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
metadata := struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
@ -31,6 +51,6 @@ func metadataHandleFunc(domain string) http.HandlerFunc {
CodeChallengeMethodsSupported: []string{"S256"},
}
sendJSONResponse(writer, http.StatusOK, metadata)
}
sendResponse(writer, http.StatusOK, metadata)
})
}