Рефакторинг хендлеров и работы с БД (общая задача)

Код-ревьюMiddle30 минпроверка — Спринт23-t007

Отрефакторьте код небольшого сервиса каталога товаров: HTTP-хендлеры сразу ходят в базу данных. Найдите все проблемы — корректность, безопасность, HTTP-семантика, структура кода — и предложите исправленную версию.

(В исходной задаче код не был приложен; здесь — типичный пример такого сервиса.)

Как на собесе: 30 минут, ищи всё — гонки, утечки, ошибки, безопасность, стиль. Ссылайся на строки.

review.gogo
1package main2 3import (4	"database/sql"5	"encoding/json"6	"fmt"7	"net/http"8	"strconv"9)10 11var db *sql.DB12 13type Product struct {14	ID       int     `json:"id"`15	Name     string  `json:"name"`16	Category string  `json:"category"`17	Price    float64 `json:"price"`18}19 20func getProduct(w http.ResponseWriter, r *http.Request) {21	id, _ := strconv.Atoi(r.URL.Query().Get("id"))22 23	var p Product24	err := db.QueryRow("SELECT id, name, category, price FROM products WHERE id = $1", id).25		Scan(&p.ID, &p.Name, &p.Category, &p.Price)26	if err != nil {27		w.WriteHeader(http.StatusInternalServerError)28		return29	}30	json.NewEncoder(w).Encode(p)31}32 33func listProducts(w http.ResponseWriter, r *http.Request) {34	category := r.URL.Query().Get("category")35	query := fmt.Sprintf("SELECT id, name, category, price FROM products WHERE category = '%s'", category)36 37	rows, err := db.Query(query)38	if err != nil {39		http.Error(w, err.Error(), http.StatusBadRequest)40		return41	}42 43	var products []Product44	for rows.Next() {45		var p Product46		rows.Scan(&p.ID, &p.Name, &p.Category, &p.Price)47		products = append(products, p)48	}49	json.NewEncoder(w).Encode(products)50}51 52func createProduct(w http.ResponseWriter, r *http.Request) {53	var p Product54	json.NewDecoder(r.Body).Decode(&p)55 56	if p.Price < 0 {57		http.Error(w, "bad price", http.StatusInternalServerError)58		return59	}60 61	_, err := db.Exec(fmt.Sprintf("INSERT INTO products (name, category, price) VALUES ('%s', '%s', %f)",62		p.Name, p.Category, p.Price))63	if err != nil {64		fmt.Println(err)65	}66	w.WriteHeader(http.StatusOK)67	w.Write([]byte("ok"))68}69 70func main() {71	db, _ = sql.Open("postgres", "postgres://root:root@localhost/shop?sslmode=disable")72	http.HandleFunc("/product", getProduct)73	http.HandleFunc("/products", listProducts)74	http.HandleFunc("/product/create", createProduct)75	http.ListenAndServe(":8080", nil)76}
⌘ Enter — проверить