package main import ( "database/sql" "encoding/json" "log" "net/http" "strconv" "github.com/gorilla/mux" _ "github.com/mattn/go-sqlite3" "github.com/rs/cors" ) type Review struct { ID int `json:"id"` ProductID int `json:"product_id"` Username string `json:"username"` Rating int `json:"rating"` Comment string `json:"comment"` CreatedAt string `json:"createdAt"` } var db *sql.DB func main() { var err error db, err = sql.Open("sqlite3", "./reviews.db") if err != nil { log.Fatal("Ошибка открытия БД:", err) } createTable() r := mux.NewRouter() r.HandleFunc("/product/{product_id:[0-9]+}", getReviews).Methods("GET") r.HandleFunc("/product/{product_id:[0-9]+}", addReview).Methods("POST") corsHandler := cors.New(cors.Options{ AllowedOrigins: []string{"http://localhost:3000"}, AllowedMethods: []string{"GET", "POST"}, AllowedHeaders: []string{"Content-Type", "Authorization"}, AllowCredentials: true, }).Handler(r) log.Println("Server is running on port 8080...") if err := http.ListenAndServe(":8080", corsHandler); err != nil { log.Fatal("Ошибка запуска сервера:", err) } } func createTable() { _, err := db.Exec(` CREATE TABLE IF NOT EXISTS reviews ( id INTEGER PRIMARY KEY AUTOINCREMENT, product_id INTEGER NOT NULL, username TEXT NOT NULL, rating INTEGER NOT NULL CHECK(rating >= 1 AND rating <= 5), comment TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); `) if err != nil { log.Fatal("Ошибка создания таблицы:", err) } } func addReview(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) productID, err := strconv.Atoi(vars["product_id"]) if err != nil { http.Error(w, "Некорректный product_id", http.StatusBadRequest) log.Println("Ошибка преобразования product_id:", err) return } var review Review if err := json.NewDecoder(r.Body).Decode(&review); err != nil { http.Error(w, "Некорректный JSON", http.StatusBadRequest) log.Println("Ошибка декодирования JSON:", err) return } // Игнорируем переданный в JSON product_id и устанавливаем его из URL review.ProductID = productID log.Printf("Добавление отзыва для товара %d: %+v", productID, review) stmt, err := db.Prepare(` INSERT INTO reviews (product_id, username, rating, comment, created_at) VALUES (?, ?, ?, ?, datetime('now')) `) if err != nil { http.Error(w, "Ошибка при подготовке SQL-запроса", http.StatusInternalServerError) log.Println("Ошибка при подготовке запроса:", err) return } defer stmt.Close() result, err := stmt.Exec(review.ProductID, review.Username, review.Rating, review.Comment) if err != nil { http.Error(w, "Ошибка при добавлении отзыва", http.StatusInternalServerError) log.Println("Ошибка при выполнении SQL-запроса:", err) return } rowsAffected, _ := result.RowsAffected() log.Printf("Добавлено строк: %d для товара %d", rowsAffected, productID) // Возвращаем созданный отзыв w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(review) } func getReviews(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) productID := vars["product_id"] log.Printf("Получение отзывов для товара %s", productID) rows, err := db.Query(` SELECT id, product_id, username, rating, comment, created_at FROM reviews WHERE product_id = ? ORDER BY created_at DESC `, productID) if err != nil { http.Error(w, "Ошибка при получении отзывов", http.StatusInternalServerError) log.Println("Ошибка при запросе отзывов:", err) return } defer rows.Close() var reviews []Review for rows.Next() { var review Review if err := rows.Scan(&review.ID, &review.ProductID, &review.Username, &review.Rating, &review.Comment, &review.CreatedAt); err != nil { http.Error(w, "Ошибка при обработке данных", http.StatusInternalServerError) log.Println("Ошибка при сканировании строк:", err) return } reviews = append(reviews, review) } log.Printf("Найдено %d отзывов для товара %s", len(reviews), productID) // Всегда возвращаем JSON массив, даже если он пустой w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(reviews) }