Start creating struct-based JSON encoding for API endpoints

This commit is contained in:
Eli Ribble 2026-03-04 18:30:21 +00:00
parent daa8cb1748
commit 438c946bad
No known key found for this signature in database
3 changed files with 124 additions and 0 deletions

64
api/handler.go Normal file
View file

@ -0,0 +1,64 @@
package api
import (
"context"
"encoding/json"
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/auth"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/html"
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
"github.com/Gleipnir-Technology/nidus-sync/platform"
"github.com/rs/zerolog/log"
)
type handlerFunctionGet[T any] func(context.Context, *http.Request, *models.Organization, *models.User) (*T, *nhttp.ErrorWithStatus)
type wrappedHandler func(http.ResponseWriter, *http.Request)
type contentAuthenticated[T any] struct {
C T
Config html.ContentConfig
User platform.User
}
type ErrorAPI struct {
Message string `json:"message"`
}
// w http.ResponseWriter, r *http.Request, u *models.User) {
func authenticatedHandlerJSON[T any](f handlerFunctionGet[T]) http.Handler {
return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u *models.User) {
ctx := r.Context()
org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if org == nil {
http.Error(w, "nil org", http.StatusInternalServerError)
return
}
var body []byte
resp, e := f(ctx, r, org, u)
w.Header().Set("Content-Type", "application/json")
//log.Info().Str("template", template).Err(e).Msg("handler done")
if e != nil {
log.Warn().Int("status", e.Status).Err(e).Str("user message", e.Message).Msg("Responding with an error from sync pages")
body, err = json.Marshal(ErrorAPI{Message: e.Error()})
if err != nil {
log.Error().Err(err).Msg("failed to marshal error")
http.Error(w, "{\"message\": \"boom. I can't even tell you what went wrong\"}", http.StatusInternalServerError)
return
}
http.Error(w, string(body), e.Status)
return
}
body, err = json.Marshal(resp)
if err != nil {
http.Error(w, "{\"message\": \"failed to marshal json\"}", http.StatusInternalServerError)
return
}
w.Write(body)
})
}

15
api/signal.go Normal file
View file

@ -0,0 +1,15 @@
package api
import (
"context"
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentListSignal struct{}
func listSignal(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*contentListSignal, *nhttp.ErrorWithStatus) {
return nil, nil
}

45
auth/content.go Normal file
View file

@ -0,0 +1,45 @@
package auth
import (
"context"
"strings"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/notification"
"github.com/Gleipnir-Technology/nidus-sync/platform"
)
func ContentForUser(ctx context.Context, user *models.User) (platform.User, error) {
notifications, err := notification.ForUser(ctx, user)
if err != nil {
return platform.User{}, err
}
org := user.R.Organization
var organization platform.Organization
if org != nil {
organization.ID = int(org.ID)
organization.Name = org.Name
}
return platform.User{
DisplayName: user.DisplayName,
Initials: extractInitials(user.DisplayName),
Notifications: notifications,
Organization: organization,
Role: user.Role.String(),
Username: user.Username,
}, nil
}
func extractInitials(name string) string {
parts := strings.Fields(name)
var initials strings.Builder
for _, part := range parts {
if len(part) > 0 {
initials.WriteString(strings.ToUpper(string(part[0])))
}
}
return initials.String()
}