Конвертировать строки SQL в формат JSON в Go - PullRequest
3 голосов
/ 17 марта 2019

В REST API, который я разрабатываю, есть конечная точка /courses, которая возвращает некоторые данные, запрошенные из таблицы SQL в формате JSON. Однако я не смог найти способ преобразовать запрошенные данные (строки) в JSON.

func GetCoursesEndpoint(w http.ResponseWriter, req *http.Request) {
  db, err := sql.Open("mysql", "root:@/academy")
  checkErr(err)

  rows, err := db.Query("SELECT course_name,price FROM course;")
  checkErr(err)

  //how to convert returned rows to JSON?
  msg, err := json.Marshal(rows)
  checkErr(err)

  json.NewEncoder(w).Encode(msg)
  return  
}

1 Ответ

2 голосов
/ 17 марта 2019

Экземпляр типа *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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...