refactor: extract API handlers into internal packages
Move HTTP handler logic out of main into internal api and server packages, slimming main to a thin entrypoint. Bundles bug fixes: login nil-panic, empty-password validation, chirp sort ordering, duplicate-email 409, and restricting the file server to the assets directory.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/StevanFreeborn/chirpy/internal/api"
|
||||
"github.com/StevanFreeborn/chirpy/internal/auth"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type userUpgradeData struct {
|
||||
UserId string `json:"user_id"`
|
||||
}
|
||||
|
||||
type webhookEvent struct {
|
||||
Event string `json:"event"`
|
||||
Data any `json:"-"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON captures the raw event data so it can be decoded into the
|
||||
// concrete type for the event name.
|
||||
func (p *webhookEvent) UnmarshalJSON(b []byte) error {
|
||||
type Alias webhookEvent
|
||||
|
||||
aux := &struct {
|
||||
*Alias
|
||||
RawData json.RawMessage `json:"data"`
|
||||
}{
|
||||
Alias: (*Alias)(p),
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(b, aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch p.Event {
|
||||
case "user.upgraded":
|
||||
var data userUpgradeData
|
||||
|
||||
if err := json.Unmarshal(aux.RawData, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Data = data
|
||||
default:
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleWebhooks processes Polka webhook events, e.g. upgrading a user to
|
||||
// Chirpy Red.
|
||||
func (s *Server) HandleWebhooks(w http.ResponseWriter, r *http.Request) {
|
||||
apiKey, err := auth.GetAPIKey(r.Header)
|
||||
|
||||
if err != nil || apiKey != s.polkaKey {
|
||||
api.WriteError(w, http.StatusUnauthorized, "You are not authorized to perform this action")
|
||||
return
|
||||
}
|
||||
|
||||
event, err := api.DecodeJSON[webhookEvent](r)
|
||||
|
||||
if err != nil {
|
||||
api.WriteError(w, http.StatusInternalServerError, "Unable to deserialize webhook event")
|
||||
return
|
||||
}
|
||||
|
||||
switch v := event.Data.(type) {
|
||||
case userUpgradeData:
|
||||
validUserId, err := uuid.Parse(v.UserId)
|
||||
|
||||
if err != nil {
|
||||
api.WriteError(w, http.StatusNotFound, "Unable to upgrade user")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.db.UpgradeUser(r.Context(), validUserId)
|
||||
|
||||
if err != nil {
|
||||
api.WriteError(w, http.StatusNotFound, "Unable to upgrade user")
|
||||
return
|
||||
}
|
||||
|
||||
api.WriteJSON(w, http.StatusNoContent, nil)
|
||||
default:
|
||||
api.WriteJSON(w, http.StatusNoContent, nil)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user