package main import ( "encoding/json" "log" "net/http" "strconv" "sync" "time" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" ) type Task struct { ID int `json:"id"` Title string `json:"title"` Description string `json:"description"` Status string `json:"status"` Priority string `json:"priority"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } type TaskStore struct { mu sync.RWMutex tasks map[int]Task nextID int } func NewTaskStore() *TaskStore { store := &TaskStore{ tasks: make(map[int]Task), nextID: 1, } // Add some sample tasks now := time.Now() store.tasks[1] = Task{ ID: 1, Title: "Set up development environment", Description: "Install all necessary tools and dependencies for the project", Status: "completed", Priority: "high", CreatedAt: now.Add(-48 * time.Hour), UpdatedAt: now.Add(-24 * time.Hour), } store.tasks[2] = Task{ ID: 2, Title: "Design database schema", Description: "Create the initial database schema for task management", Status: "in_progress", Priority: "high", CreatedAt: now.Add(-24 * time.Hour), UpdatedAt: now, } store.tasks[3] = Task{ ID: 3, Title: "Implement user authentication", Description: "Add JWT-based authentication system", Status: "pending", Priority: "medium", CreatedAt: now.Add(-12 * time.Hour), UpdatedAt: now.Add(-12 * time.Hour), } store.nextID = 4 return store } func (s *TaskStore) GetAll() []Task { s.mu.RLock() defer s.mu.RUnlock() tasks := make([]Task, 0, len(s.tasks)) for _, task := range s.tasks { tasks = append(tasks, task) } return tasks } func (s *TaskStore) Get(id int) (Task, bool) { s.mu.RLock() defer s.mu.RUnlock() task, ok := s.tasks[id] return task, ok } func (s *TaskStore) Create(task Task) Task { s.mu.Lock() defer s.mu.Unlock() task.ID = s.nextID task.CreatedAt = time.Now() task.UpdatedAt = time.Now() if task.Status == "" { task.Status = "pending" } if task.Priority == "" { task.Priority = "medium" } s.tasks[task.ID] = task s.nextID++ return task } func (s *TaskStore) Delete(id int) bool { s.mu.Lock() defer s.mu.Unlock() if _, ok := s.tasks[id]; ok { delete(s.tasks, id) return true } return false } type APIResponse struct { Success bool `json:"success"` Data interface{} `json:"data,omitempty"` Error string `json:"error,omitempty"` } func respondJSON(w http.ResponseWriter, status int, payload interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(payload) } func main() { store := NewTaskStore() r := chi.NewRouter() // Middleware r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(middleware.RequestID) r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"http://localhost:3000", "http://localhost:8080", "*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, ExposedHeaders: []string{"Link"}, AllowCredentials: true, MaxAge: 300, })) // Health check r.Get("/health", func(w http.ResponseWriter, r *http.Request) { respondJSON(w, http.StatusOK, APIResponse{Success: true, Data: "healthy"}) }) // API routes r.Route("/api", func(r chi.Router) { r.Route("/tasks", func(r chi.Router) { r.Get("/", func(w http.ResponseWriter, r *http.Request) { tasks := store.GetAll() respondJSON(w, http.StatusOK, APIResponse{Success: true, Data: tasks}) }) r.Post("/", func(w http.ResponseWriter, r *http.Request) { var task Task if err := json.NewDecoder(r.Body).Decode(&task); err != nil { respondJSON(w, http.StatusBadRequest, APIResponse{ Success: false, Error: "Invalid request body", }) return } if task.Title == "" { respondJSON(w, http.StatusBadRequest, APIResponse{ Success: false, Error: "Title is required", }) return } created := store.Create(task) respondJSON(w, http.StatusCreated, APIResponse{Success: true, Data: created}) }) r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) { idStr := chi.URLParam(r, "id") id, err := strconv.Atoi(idStr) if err != nil { respondJSON(w, http.StatusBadRequest, APIResponse{ Success: false, Error: "Invalid task ID", }) return } task, ok := store.Get(id) if !ok { respondJSON(w, http.StatusNotFound, APIResponse{ Success: false, Error: "Task not found", }) return } respondJSON(w, http.StatusOK, APIResponse{Success: true, Data: task}) }) r.Delete("/{id}", func(w http.ResponseWriter, r *http.Request) { idStr := chi.URLParam(r, "id") id, err := strconv.Atoi(idStr) if err != nil { respondJSON(w, http.StatusBadRequest, APIResponse{ Success: false, Error: "Invalid task ID", }) return } if !store.Delete(id) { respondJSON(w, http.StatusNotFound, APIResponse{ Success: false, Error: "Task not found", }) return } respondJSON(w, http.StatusOK, APIResponse{Success: true, Data: "Task deleted"}) }) }) }) log.Println("Starting server on :8080") if err := http.ListenAndServe(":8080", r); err != nil { log.Fatal(err) } }