- Add error handling for JSON encoding in all backend handlers - Add CORS support to backend server - Add proxy configuration for frontend development server - Improve error handling in frontend API calls - Build frontend to create static files for backend serving - Add comprehensive error messages and user feedback Fixes issue where frontend received malformed JSON responses from backend API.
101 lines
2.4 KiB
Go
101 lines
2.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
|
|
"markdown-editor/internal/handlers"
|
|
"markdown-editor/internal/logger"
|
|
"markdown-editor/internal/storage"
|
|
"github.com/gorilla/mux"
|
|
"github.com/rs/cors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type Server struct {
|
|
logger *logrus.Logger
|
|
storage storage.Storage
|
|
handlers *handlers.Handlers
|
|
router *mux.Router
|
|
server *http.Server
|
|
dataDir string
|
|
port int
|
|
host string
|
|
}
|
|
|
|
func StartServer(dataDir string, port int, host string) error {
|
|
log := logger.NewLogger()
|
|
log.Info("Starting markdown editor server")
|
|
|
|
// Initialize storage
|
|
storage, err := storage.NewFileStorage(dataDir)
|
|
if err != nil {
|
|
log.Errorf("Failed to initialize storage: %v", err)
|
|
return err
|
|
}
|
|
|
|
// Initialize handlers
|
|
handlers := handlers.NewHandlers(log, storage)
|
|
|
|
// Create server
|
|
s := &Server{
|
|
logger: log,
|
|
storage: storage,
|
|
handlers: handlers,
|
|
dataDir: dataDir,
|
|
port: port,
|
|
host: host,
|
|
}
|
|
|
|
// Setup routes
|
|
s.setupRoutes()
|
|
|
|
// Start server
|
|
s.logger.Infof("Server starting on %s:%d", host, port)
|
|
return s.serve()
|
|
}
|
|
|
|
func (s *Server) setupRoutes() {
|
|
s.router = mux.NewRouter()
|
|
|
|
// API routes
|
|
apiRouter := s.router.PathPrefix("/api").Subrouter()
|
|
apiRouter.Handle("/files", s.handlers.ListFiles()).Methods("GET")
|
|
apiRouter.Handle("/files", s.handlers.CreateFile()).Methods("POST")
|
|
apiRouter.Handle("/files/{filename}", s.handlers.GetFile()).Methods("GET")
|
|
apiRouter.Handle("/files/{filename}", s.handlers.UpdateFile()).Methods("PUT")
|
|
apiRouter.Handle("/files/{filename}", s.handlers.DeleteFile()).Methods("DELETE")
|
|
|
|
// Static file serving
|
|
frontendDir := "frontend/build"
|
|
if frontendDirEnv := os.Getenv("FRONTEND_BUILD_DIR"); frontendDirEnv != "" {
|
|
frontendDir = frontendDirEnv
|
|
}
|
|
s.router.PathPrefix("/").Handler(http.FileServer(http.Dir(frontendDir)))
|
|
|
|
// Enable CORS
|
|
cors := cors.New(cors.Options{
|
|
AllowedOrigins: []string{"http://localhost:3000", "http://localhost:8080"},
|
|
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
|
AllowedHeaders: []string{"Content-Type", "Authorization"},
|
|
AllowCredentials: true,
|
|
})
|
|
s.router.Use(cors.Handler)
|
|
}
|
|
|
|
func (s *Server) serve() error {
|
|
s.server = &http.Server{
|
|
Addr: fmt.Sprintf("%s:%d", s.host, s.port),
|
|
Handler: s.router,
|
|
}
|
|
|
|
return s.server.ListenAndServe()
|
|
}
|
|
|
|
func (s *Server) Shutdown(ctx context.Context) error {
|
|
s.logger.Info("Shutting down server...")
|
|
return s.server.Shutdown(ctx)
|
|
}
|