Поиск SO для Общий REST API Golang дает 0 результатов. Поиск в Google дает 2 результата. Так что этот вопрос, возможно, неправильно сформулирован или его невозможно решить на Голанге.
Моя цель - не повторять один и тот же код снова и снова. Поэтому я пытаюсь сделать код на Голанге как можно более общим. Напишите один раз, используйте много.
Это моя первая попытка создать общий REST API для выбора в Golang. Приведенный ниже код дает почти то, что я хочу:
Но результат отображается в Терминале. Понятия не имею, как перенаправить результат в браузер.
package main
import (
"fmt"
"log"
"net/http"
"database/sql"
"time"
_ "github.com/lib/pq"
)
var db *sql.DB
func main() {
Connect()
http.HandleFunc("/", Query)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func Connect() {
const (
host = "127.0.0.1"
port = 5432
user = "test"
password = "test"
dbname = "Test")
login := fmt.Sprintf("host=%s port=%d user=%s "+"password=%s dbname=%s sslmode=require", host, port, user, password, dbname)
var err error
db, err = sql.Open("postgres", login)
if err != nil {
log.Fatalln(err)
}
err = db.Ping()
if err != nil {
panic(err)
}
func Query(w http.ResponseWriter, r *http.Request) {
var query string
switch r.URL.String() {
case "/getuser":
query = "select * from getuser()"
case "/getco":
query = "select * from getco()"
case "/etc"
query = "select * from etc"
default:
query = ""
}
var err error
var rows *sql.Rows
rows, err = db.Query(query)
if err != nil {
http.Error(w, http.StatusText(500), 500)
return
}
defer rows.Close()
cols, err := rows.Columns()
vals := make([]interface{}, len(cols))
for i := 0; i < len(cols); i++ {
vals[i] = new(interface{})
if i != 0 {
fmt.Print("\t")
}
fmt.Print(cols[i])
}
fmt.Println()
for rows.Next() {
err = rows.Scan(vals...)
if err != nil {
fmt.Println(err)
continue
}
for i := 0; i < len(vals); i++ {
if i != 0 {
fmt.Print("\t")
}
printValue(vals[i].(*interface{}))
}
fmt.Println()
}
func printValue(pval *interface{}) {
switch v := (*pval).(type) {
case nil:
fmt.Print("NULL")
case bool:
if v {
fmt.Print("1")
} else {
fmt.Print("0")
}
case []byte:
fmt.Print(string(v))
case time.Time:
fmt.Print(v.Format("2006-01-02"))
default:
fmt.Print(v)
}
}
Каждая попытка записи в браузер выдает различные типы ошибок:
fmt.Printf("%s\n", vals...)
Мои вопросы
Да, это перенаправляет "результат" в браузер. Но только мусорный текст вроде «шаблон%! (EXTRA * interface {} = 0xc4201aa2b0 etc». В то же время результат по-прежнему выводится в Терминал. Дальнейшие подсказки?
Вы используете безопасный тип языка, чтобы попытаться игнорировать безопасность типов. Найдите молоток получше или сгенерируйте код.
@peter Не могли бы вы рассказать об этом подробнее? Что небезопасно и почему?
Я не сказал, что это небезопасно. Я имел в виду, что есть лучшие варианты, чем использование статически типизированного языка, чтобы затем игнорировать систему типов, помещая interface {} повсюду. Это будет грязно. Вы также можете использовать язык с динамической типизацией, такой как Ruby, Python, PHP.
@peter "rows.Columns ()" - это динамическая (?) команда из golang "database / sql". Как стандартная команда может быть беспорядочной? Простите меня, но я новичок на Голанге и только пытаюсь понять.
Беспорядок заключается в том, как вы должны иметь дело с фактическими строками, а не с именами столбцов. Это намного чище и проще, если вы знаете, с чем работаете. А вы еще даже не написали код для вставок. Попробуй сам. Напишите неуниверсальный код для одной из конечных точек и сравните. Вы увидите, что это намного короче и проще.





написать ответ с соответствующими HTTP-слушателями && кодом состояния
import "net/http"
func writeResponse(w http.ResponseWriter, contents []byte) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, contents)
}
звучит немного непонятно, извините
1. Итак, вызов другой функции вне "func Query" ?. Как? 2. Как получить общий REST API. Я пишу один раз, использую много раз. Ссылки, подсказки или что-то еще.
Я бы порекомендовал использовать существующие пакеты, такие как "mux", для вызова REST API в браузере. В качестве быстрой демонстрации, как это можно сделать следующим образом:
ваш restapi.go cound имеет следующие API:
func SampleAPI(w http.ResponseWriter, r *http.Request) { //Assuming this is a POST request
var example SomeSruct
_ = json.NewDecoder(r.Body).Decode(&example) //Decode the POST body
result := someLogicFunction(example) //call your generic function
json.NewEncoder(w).Encode(result) //encode the result to pass it back to browser
}
Теперь предположим, что вы пишете main.go и используете пакет mux, вот пример того, как вы бы назвали это
main.go
func main() {
router := mux.NewRouter()
router.HandleFunc("/testFunc",restapi.SampleAPI).Methods("POST") //This creates the route for your http request
handler := cros.Default().Handler(router) //You will need this if you plan to deploy it in a server and call it externally for testing locally you don't need this
log.Fatal(http.ListenAndServe(":8080", handler)) //Port that the router is listening to
}
Теперь обратите внимание, что вам нужно будет импортировать пакеты «github.com/gorilla/mux» и «github.com/rs/cors», чтобы использовать их, но таким образом вы можете создавать REST API, к которым может получить доступ браузер. Точно так же вы можете создать метод GET и использовать параметры, которые вы можете получить в своей функции и выполнить любой логический шаг.
Если вы соберете и установите приведенный выше код, вы можете выполнить POST в локальный: 8080 / testFunc через http с помощью любого веб-приложения и получить результаты в своем браузере. Если у вас был запрос GET, вы могли напрямую ввести URL-адрес в браузере и увидеть результат.
разделите Запрос БД и Подключение к БД в отдельных функциях. при записи вывода в стандартный вывод с использованием
fmt.Printf()используйтеfmt.Fprintf(w, "pattern", vars), это будет записывать вывод в HTTP-ответ.