Экземпляр типа *sql.Rows
не может быть преобразован в json напрямую .Он не реализует интерфейс json.Marshaler
, и все его поля не экспортированы и поэтому недоступны для пакета encoding/json
.
Вам нужно сканировать содержимоестроки в промежуточный объект, который можно маршалировать, а затем упорядочить этот объект в json.
Итак, сначала начните с объявления типа, который будет представлять этот «промежуточный» объект, например:
type Course struct {
Name string
Price int
}
Затем, поскольку вы выбираете несколько записей, вам нужно будет выполнить итерацию по объекту строк, используя его метод Next
, и на каждой итерации сканировать содержимое записи в экземпляр типа Course
.
var courses []*Course // declare a slice of courses that will hold all of the Course instances scanned from the rows object
for rows.Next() { // this stops when there are no more rows
c := new(Course) // initialize a new instance
err := rows.Scan(&c.Name, &c.Price) // scan contents of the current row into the instance
if err != nil {
return err
}
courses = append(courses, c) // add each instance to the slice
}
if err := rows.Err(); err != nil { // make sure that there was no issue during the process
return err
}
И, наконец, вы можете превратить срез courses
в json, передав его кодировщику.
if err := json.NewEncoder(w).Encode(courses); err != nil {
log.Println(err)
}
Если вы примените вышеуказанные предложения к своему обработчикувы должны начать видеть ожидаемый результат или что-то подобное ... Однако у вашего обработчика есть пара других проблем, которые вам нужно решить, если вы не хотите, чтобы ваши приложениякатион для сбоя.
Первый:
db, err := sql.Open("mysql", "root:@/academy")
Нет необходимости открывать соединение каждый раз, когда выполняется обработчик, и поэтому было бы намного лучше, если бы вы переместили open-db-connectionкод за пределами обработчика и просто сделать переменную db
доступной для обработчика.Однако, если вы хотите продолжать открывать соединение каждый раз, когда вам нужно обязательно закрывать его каждый раз, в противном случае у вас закончатся доступные соединения.
Секунда:
rows, err := db.Query("SELECT course_name,price FROM course;")
Возвращенный объект rows
должен быть закрыт по тем же причинам, по которым вам необходимо закрыть дескриптор db
, если вы продолжаете открывать его каждый раз, то есть у вас заканчиваются доступные соединения, и ваше приложение падает.
Итак, более полная версия кода, которая должна работать правильно, будет выглядеть так:
var db *sql.DB // declare a global variable that will be used by all handlers
func init() {
var err error
db, err = sql.Open("mysql", "root:@/academy") // initialize the global connection
if err != nil {
panic(err)
}
}
type Course struct {
Name string
Price int
}
func GetCoursesEndpoint(w http.ResponseWriter, req *http.Request) {
rows, err := db.Query("SELECT course_name,price FROM course;")
if err != nil {
fmt.Println(err)
return
}
defer rows.Close() // make sure rows is closed when the handler exits
var courses []*Course
for rows.Next() {
c := new(Course)
err := rows.Scan(&c.Name, &c.Price)
if err != nil {
fmt.Println(err)
return
}
courses = append(courses, c)
}
if err := rows.Err(); err != nil {
fmt.Println(err)
return
}
if err := json.NewEncoder(w).Encode(courses); err != nil {
fmt.Println(err)
}
return
}