messaging-center/internal/api/router.go

91 lines
2.3 KiB
Go

package api
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/inou-ai/messaging-center/internal/core"
"github.com/inou-ai/messaging-center/internal/store"
)
// Server is the HTTP API server.
type Server struct {
config *core.Config
store *store.Store
oauth *OAuthProvider
router chi.Router
}
// NewServer creates a new API server.
func NewServer(cfg *core.Config, s *store.Store) *Server {
srv := &Server{
config: cfg,
store: s,
oauth: NewOAuthProvider(&cfg.OAuth),
}
srv.setupRoutes()
return srv
}
// ServeHTTP implements http.Handler.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.router.ServeHTTP(w, r)
}
func (s *Server) setupRoutes() {
r := chi.NewRouter()
// Middleware
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.RealIP)
// Health endpoints (no auth)
r.Get("/health", s.handleHealth)
r.Get("/ready", s.handleReady)
// OAuth token endpoint
r.Post("/oauth/token", s.oauth.HandleToken)
// API v1
r.Route("/api/v1", func(r chi.Router) {
// Messages
r.Route("/messages", func(r chi.Router) {
r.With(s.oauth.RequireAuth("messages:read")).Get("/", s.handleListMessages)
r.With(s.oauth.RequireAuth("messages:read")).Get("/{id}", s.handleGetMessage)
r.With(s.oauth.RequireAuth("messages:write")).Post("/", s.handleCreateMessage)
})
// Commands
r.Route("/commands", func(r chi.Router) {
r.With(s.oauth.RequireAuth("commands:write")).Post("/", s.handleCreateCommand)
r.With(s.oauth.RequireAuth("commands:write")).Get("/{id}", s.handleGetCommand)
})
// Channels
r.Route("/channels", func(r chi.Router) {
r.With(s.oauth.RequireAuth("admin")).Get("/", s.handleListChannels)
})
})
s.router = r
}
// handleHealth returns 200 OK if the server is running.
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}
// handleReady returns 200 OK if the server is ready to accept traffic.
func (s *Server) handleReady(w http.ResponseWriter, r *http.Request) {
if err := s.store.Ping(); err != nil {
writeJSON(w, http.StatusServiceUnavailable, map[string]string{
"status": "not ready",
"error": err.Error(),
})
return
}
writeJSON(w, http.StatusOK, map[string]string{"status": "ready"})
}