retrieving data from json response from an API - json

I'm trying to get data from json response by storing it in some structs (Airport + coordinates) but I don't know how to deal with that since I'm not good enough with maps and interfaces. The code is showing no errors but MapofAirports is completely empty here is the code:
package main
import (
//"api/client"
//"api/client/clienterrors"
//"api/client/openstreetmap"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math"
"net/http"
"os"
"strconv"
"strings"
)
type Coordinates struct {
Longitude string `json:"lon"`
Latitude string `json:"lat"`
}
type Airport struct {
Co Coordinates `json:"location"`
IATACode string `json:"id"`
Distance float64 `json:"distance"` // distance to coordinates in kilometer
}
func GetCoordinatesFromURL(url string) (float64, float64) {
parts := strings.Split(url, "=")
lat0 := strings.Split(parts[2], "&")
lon0 := strings.Split(parts[3], "&")
lat1, _ := strconv.ParseFloat(lat0[0], 64)
lon1, _ := strconv.ParseFloat(lon0[0], 64)
return lat1, lon1
}
func CalcDistance(lat1 float64, long1 float64, lat2 float64, long2 float64) float64 {
var latitude1 = lat1 * math.Pi / 180
var latitude2 = lat2 * math.Pi / 180
var longitude1 = long1 * math.Pi / 180
var longitude2 = long2 * math.Pi / 180
var R = 6371.0
var d = R * math.Acos(math.Cos(latitude1)*math.Cos(latitude2)*math.Cos(longitude2-longitude1)+math.Sin(latitude1)*math.Sin(latitude2))
return d
}
func main() {
var Locations []Airport
Locations = make([]Airport, 0)
var url = fmt.Sprintf("https://api.skypicker.com/locations?type=radius&lat=40.730610&lon=-73.935242&radius=250&location_types=airport&limit=3&sort=id&active_only=true")
UrlLat, UrlLon := GetCoordinatesFromURL(url)
resp, err := http.Get(url)
if err != nil {
panic(err.Error())
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
var airportsJsonResponse interface{}
err = json.Unmarshal(body, &airportsJsonResponse)
MapofAirports, ok := airportsJsonResponse.([]interface{})
if ok {
lenAiroMap := len(MapofAirports)
locationsMaps := make(map[int]map[string]interface{})
for i := 0; i < lenAiroMap; i++ {
locationsMaps[i] = MapofAirports[i].(map[string]interface{})
}
var coords Coordinates
for i := 0; i < lenAiroMap; i++ {
if longitude, ok0 := locationsMaps[i]["lon"].(string); ok0 {
if latitude, ok1 := locationsMaps[i]["lat"].(string); ok1 {
coords = Coordinates{longitude, latitude}
}
}
code := locationsMaps[i]["id"].(string)
latFromCoordinates, _ := strconv.ParseFloat(Locations[i].Co.Latitude, 64)
lonFromCoordinates, _ := strconv.ParseFloat(Locations[i].Co.Longitude, 64)
dist := CalcDistance(latFromCoordinates, lonFromCoordinates, UrlLat, UrlLon)
Locations = append(Locations, Airport{
Co: coords,
IATACode: code,
Distance: dist,
})
}
}
LocationsJson, err := json.Marshal(Locations)
if err != nil {
log.Fatal("Cannot encode to JSON ", err)
}
fmt.Fprintf(os.Stdout, "%s", LocationsJson)
}
screenshot of json response
in the screenshot this is the json response we have, and I'm processing like this:
{ locations[],meta,last_refresh,results_retrieved } ==> location : { id , location + distance(calculated with a function) }

Change this line MapofAirports, ok := airportsJsonResponse.([]interface{}) to this
MapofAirports, ok := airportsJsonResponse.(map[string]interface{})
If you place a break point at this line you will see type of airportsJsonResponse is map[string]interface{}.
And you will have to change this lines into key value iteration
for i := 0; i < lenAiroMap; i++ {
locationsMaps[i] = MapofAirports[i].(map[string]interface{})
}
in to sth like below :
lenAiroMap := len(MapofAirports)
locationsMaps := make([]map[string]interface{},lenAiroMap)
for i, value := range MapofAirports["locations"].([]interface{}) {
converted := value.(map[string]interface{})
locationsMaps[i] = converted
}

this is my last update and while running the program it panics at unmarshaling step
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"math"
"net/http"
"strconv"
"strings"
)
type Coordinates struct {
Longitude string `json:"lon"`
Latitude string `json:"lat"`
}
type Airport struct {
Co Coordinates `json:"location"`
IATACode string `json:"id"`
Distance float64 `json:"distance"` // distance to coordinates in kilometer
}
type Response struct {
Locations []Airport `json:"locations"`
// add all the other fields you care about
}
func GetCoordinatesFromURL(url string) (float64, float64) {
parts := strings.Split(url, "=")
lat0 := strings.Split(parts[2], "&")
lon0 := strings.Split(parts[3], "&")
lat1, _ := strconv.ParseFloat(lat0[0], 64)
lon1, _ := strconv.ParseFloat(lon0[0], 64)
return lat1, lon1
}
func CalcDistance(lat1 float64, long1 float64, lat2 float64, long2 float64) float64 {
var latitude1 = lat1 * math.Pi / 180
var latitude2 = lat2 * math.Pi / 180
var longitude1 = long1 * math.Pi / 180
var longitude2 = long2 * math.Pi / 180
var R = 6371.0
var d = R * math.Acos(math.Cos(latitude1)*math.Cos(latitude2)*math.Cos(longitude2-longitude1)+math.Sin(latitude1)*math.Sin(latitude2))
return d
}
func main() {
var url = fmt.Sprintf("https://api.skypicker.com/locations?type=radius&lat=40.730610&lon=-73.935242&radius=250&location_types=airport&limit=3&sort=id&active_only=true")
UrlLat, UrlLon := GetCoordinatesFromURL(url)
resp, err := http.Get(url)
if err != nil {
panic(err.Error())
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
res := &Response{}
if err := json.Unmarshal(data, res); err != nil {
panic(err)
}
fmt.Println(res.Locations)
for i, item := range res.Locations {
latt,_ := strconv.ParseFloat(item.Co.Latitude, 64)
lonn,_ :=strconv.ParseFloat(item.Co.Longitude, 64)
res.Locations[i].Distance = CalcDistance(latt,lonn , UrlLat, UrlLon)
}
fmt.Println("after calculate distance")
fmt.Println(res.Locations)
}
what's wrong with that ?

Related

Combining data from multiple cells into one JSON object

I am trying to combine data from multiple cells from an excel spreadsheet into one JSON encoded string. I cannot figure out how to do so, the code below is creating a new JSON object per cell. How do I differentiate the cells to combine into the same JSON string?
package main
import (
"fmt"
"github.com/tealeg/xlsx"
"encoding/json"
)
func main() {
excelFileName := "/Users/isaacmelton/Desktop/Test_Data.xlsx"
xlFile, err := xlsx.OpenFile(excelFileName)
if err != nil {
fmt.Printf("Cannot parse data")
}
for _, sheet := range xlFile.Sheets {
for _, row := range sheet.Rows {
fmt.Printf("\n")
for x, cell := range row.Cells {
if x == 3 || x == 5 {
data := map[string]string{"d_name": cell.String(), "name": cell.String()}
json_data, _ := json.Marshal(data)
fmt.Println(string(json_data))
}
}
}
}
}
Running the above code results in the following:
{"foo":"cell1","bar":"cell1"}
{"foo":"cell2","bar":"cell2"}
I expect something like this:
{"foo":"cell1", "bar":"cell2"}
If I right understand your request you just need to define root element, add cells into it and marshal this element rather than individual cells.
root := []map[string]string{}
for x, cell := range row.Cells {
if x == 3 || x == 5 {
root = append(root, map[string]string{"d_name": cell.String(), "name": cell.String()})
}
}
json_data, _ := json.Marshal(root)
fmt.Println(string(json_data))
http://play.golang.org/p/SHnShHvW_0
You may use
a, err := row.Cells[3].String()
b, err := row.Cells[5].String()
Like this working code:
package main
import (
"encoding/json"
"fmt"
"github.com/tealeg/xlsx"
)
func main() {
xlFile, err := xlsx.OpenFile(`Test_Data.xlsx`)
if err != nil {
panic(err)
}
for _, sheet := range xlFile.Sheets {
for _, row := range sheet.Rows {
//for x, cell := range row.Cells {
//if x == 3 || x == 5 {
a, err := row.Cells[3].String()
if err != nil {
panic(err)
}
b, err := row.Cells[5].String()
if err != nil {
panic(err)
}
data := map[string]string{"d_name": a, "name": b}
json_data, err := json.Marshal(data)
if err != nil {
panic(err)
}
fmt.Println(string(json_data))
//}
//}
}
}
}
output:
{"d_name":"1000","name":"a"}
{"d_name":"2000","name":"b"}
{"d_name":"3000","name":"c"}
{"d_name":"4000","name":"d"}
{"d_name":"5000","name":"e"}
input file content:
1 10 100 1000 10000 a
2 20 200 2000 20000 b
3 30 300 3000 30000 c
4 40 400 4000 40000 d
5 50 500 5000 50000 e

Retrieve a record from mysql in golang using database/sql

I'm trying to retrieve a record from mysql table and marshal it to json.
But i gotted the error that says : ".\main.go:67: no new variables on left sife of :="
I'm new in Golang Plz! help me to solve out this error!
My Code is :
func GetUser(w http.ResponseWriter, r *http.Request) {
urlParams := mux.Vars(r)
id := urlParams["id"]
ReadUser := User{}
con, err := sql.Open("mysql", "root:YES#/social_network?charset=utf8")
err := con.QueryRow("select * from users where user_id=?",id).Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email )
switch {
case err == sql.ErrNoRows:
fmt.Fprintf(w,"No such user")
case err != nil:
log.Fatal(err)
default:
output, _ := json.Marshal(ReadUser)
fmt.Fprintf(w,string(output))
}
}
and Routes in main:
func main() {
gorillaRoute := mux.NewRouter()
gorillaRoute.HandleFunc("/api/user/create", CreateUser)
gorillaRoute.HandleFunc("/api/user/read/:id", GetUser)
http.Handle("/", gorillaRoute)
http.ListenAndServe(":8080", nil)
}
Here is my new Code , but again not able to get record from database table, plz help me to figure out the error OR what things i do wrong?
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"net/http"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
type API struct {
Message string "json:message"
}
type User struct {
ID int "json:id"
Name string "json:username"
Email string "json:email"
First string "json:first"
Last string "json:last"
}
func Hello(w http.ResponseWriter, r *http.Request) {
// urlParams := mux.Vars(r)
// name := urlParams["user"]
HelloMessage := "User Creation page"
message := API{HelloMessage}
output, err := json.Marshal(message)
if err != nil {
fmt.Println("Something went wrong!")
}
fmt.Fprintf(w, string(output))
}
//POST A USER INTO DB
func CreateUser(w http.ResponseWriter, r *http.Request) {
NewUser := User{}
NewUser.Name = r.FormValue("user")
NewUser.Email = r.FormValue("email")
NewUser.First = r.FormValue("first")
NewUser.Last = r.FormValue("last")
output, err := json.Marshal(NewUser)
fmt.Println(string(output))
if err != nil {
fmt.Println("Something went wrong!")
}
con, err := sql.Open("mysql", "root:YES#/social_network?charset=utf8")
sqlQuery := "INSERT INTO users set user_nickname='" + NewUser.Name + "', user_first='" + NewUser.First + "', user_last='" + NewUser.Last + "', user_email='" + NewUser.Email + "'"
q, err := con.Exec(sqlQuery)
if err != nil {
fmt.Println(err)
}
fmt.Println(q)
}
//GET USERS FROM DB
func GetUsers(w http.ResponseWriter, r *http.Request) {
db, err := sql.Open("mysql", "root:YES#/social_network?charset=utf8")
if err != nil {
panic(err)
}
err = db.Ping()
if err != nil {
panic(err)
}
defer db.Close()
rows, err := db.Query("select * from users ")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var rowBuf, _ = rows.Columns()
var cols = make([]string, len(rowBuf))
copy(cols, rowBuf)
fmt.Println(rowBuf)
var vals = make([]interface{}, len(rowBuf))
for i, _ := range rowBuf {
vals[i] = &rowBuf[i]
}
for rows.Next() {
err := rows.Scan(vals...)
if err != nil {
log.Fatal(err)
}
var m = map[string]interface{}{}
for i, col := range cols {
m[col] = vals[i]
}
obj, _ := json.Marshal(m)
//
fmt.Fprintf(w, string(obj))
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}
func GetUser(w http.ResponseWriter, r *http.Request) {
urlParams := mux.Vars(r)
id := urlParams["id"]
ReadUser := User{}
db, err := sql.Open("mysql", "root:YES#/social_network?charset=utf8")
stmt := db.QueryRow("select * from users where id = ?", id)
if err != nil {
log.Fatal(err)
}
err = stmt.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)
if err != nil {
log.Fatal(err)
}
result, err := json.Marshal(ReadUser)
fmt.Fprintf(w, string(result))
}
func main() {
gorillaRoute := mux.NewRouter()
gorillaRoute.HandleFunc("/api/user/create", CreateUser)
gorillaRoute.HandleFunc("/api/user/read", GetUsers)
gorillaRoute.HandleFunc("/api/user/:id", GetUser)
http.Handle("/", gorillaRoute)
http.ListenAndServe(":8080", nil)
}
Remove the colon : from err := as you are assigning a new value to existing variable.

Is there a better way to marshal sql rows?

I have the following struct:
type MyTable struct{
DBColA []byte `db:"cola" json:"-"`
ColA string `json:"cola"`
DBColB []byte `db:"colb" json:"-"`
ColB string `json:"colb"`
}
I map to []byte [to better handle null values in my sql][1]
When I grab the rows I need to output it as json. In order to do that I convert []byte to string:
var rows []*MyTable
if _, err := Session.Select(&rows, sql, args...); err != nil {
log.Println(err)
}
for _, row := range rows{
row.ColA = string(row.DBColA)
row.ColB = string(row.DBColB)
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(rows); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
It seems very inefficient to have DBColA and ColA in my struct and then converting DBColA to a string....I have a lot of columns. Is there a better way?
[1]: https://github.com/go-sql-driver/mysql/wiki/Examples
Have you tried gosqljson in https://github.com/elgs/gosqljson ?
See example:
```golang
package main
import (
"database/sql"
"fmt"
"github.com/elgs/gosqljson"
_ "github.com/go-sql-driver/mysql"
)
func main() {
ds := "username:password#tcp(host:3306)/db"
db, err := sql.Open("mysql", ds)
defer db.Close()
if err != nil {
fmt.Println("sql.Open:", err)
}
theCase := "lower" // "lower" default, "upper", camel
a, _ := gosqljson.QueryDbToArrayJson(db, theCase, "SELECT ID,NAME FROM t LIMIT ?,?", 0, 3)
fmt.Println(a)
// [["id","name"],["0","Alicia"],["1","Brian"],["2","Chloe"]]
m, _ := gosqljson.QueryDbToMapJson(db, theCase, "SELECT ID,NAME FROM t LIMIT ?,?", 0, 3)
fmt.Println(m)
// [{"id":"0","name":"Alicia"},{"id":"1","name":"Brian"},{"id":"2","name":"Chloe"}]
}
````

Golang Net.IP to IPv6 (from MySQL) as Decimal(39,0) Conversion?

I have a database that stores IPv4 and IPv6 addresses as decimal(39,0). I need to convert a Golang Net.IP to this format. I have done it for IPv4 as follows:
func ipv4ToInt(IPv4Addr net.IP) int64 {
bits := strings.Split(IPv4Addr.String(), ".")
b0, _ := strconv.Atoi(bits[0])
b1, _ := strconv.Atoi(bits[1])
b2, _ := strconv.Atoi(bits[2])
b3, _ := strconv.Atoi(bits[3])
var sum int64
sum += int64(b0) << 24
sum += int64(b1) << 16
sum += int64(b2) << 8
sum += int64(b3)
return sum
}
I am trying the same with IPv6:
func ipv6ToInt(IPv6Addr net.IP) Int128 {
bits := strings.Split(IPv6Addr.String(), ":")
var arr [4]int64
var arr1 [4]uint64
for i := 0; i < 4; i++ {
arr[i], _ = strconv.ParseInt(bits[i], 16, 64)
}
for i := 0; i < 4; i++ {
arr1[i], _ = strconv.ParseUint(bits[i], 16, 64)
}
int1 := arr[0]
for i := 0; i < 4; i++ {
int1 = (int1 << 16) + arr[i]
}
int2 := arr1[0]
for i := 0; i < 4; i++ {
int2 = (int2 << 16) + arr1[i]
}
var IPv6Int Int128
IPv6Int.H = int1
IPv6Int.L = int2
return IPv6Int
}
Where int128 is
type Int128 struct {
H int64
L uint64
}
The result should look like:
42540578165168461141553663388954918914
from the IPv6 addr:
2001:470:0:76::2
Thanks!
EDIT, ANSWER:
Thanks to the people in #go-nuts, the answer is as follows:
func ipv6ToInt(IPv6Addr net.IP) *big.Int {
IPv6Int := big.NewInt(0)
IPv6Int.SetBytes(IPv6Addr)
return IPv6Int
}
The same works for IPv6, just do IP.To4() first.
Thanks to the people in #go-nuts, the answer is as follows:
func ipv6ToInt(IPv6Addr net.IP) *big.Int {
IPv6Int := big.NewInt(0)
IPv6Int.SetBytes(IPv6Addr)
return IPv6Int
}
The same works for IPv4, just do IP.To4() first.

Dumping MySQL tables to JSON with Golang

Was putting together a quick dumper for MySQL to JSON in Go. However I find that everything that I retrieve from the database is a []byte array. Thus instead of native JSON integers or booleans, I'm getting everything encoded as strings.
Subset of the code:
import (
"encoding/json"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func dumpTable(w io.Writer, table) {
// ...
rows, err := Query(db, fmt.Sprintf("SELECT * FROM %s", table))
checkError(err)
columns, err := rows.Columns()
checkError(err)
scanArgs := make([]interface{}, len(columns))
values := make([]interface{}, len(columns))
for i := range values {
scanArgs[i] = &values[i]
}
for rows.Next() {
err = rows.Scan(scanArgs...)
checkError(err)
record := make(map[string]interface{})
for i, col := range values {
if col != nil {
fmt.Printf("\n%s: type= %s\n", columns[i], reflect.TypeOf(col))
switch t := col.(type) {
default:
fmt.Printf("Unexpected type %T\n", t)
case bool:
fmt.Printf("bool\n")
record[columns[i]] = col.(bool)
case int:
fmt.Printf("int\n")
record[columns[i]] = col.(int)
case int64:
fmt.Printf("int64\n")
record[columns[i]] = col.(int64)
case float64:
fmt.Printf("float64\n")
record[columns[i]] = col.(float64)
case string:
fmt.Printf("string\n")
record[columns[i]] = col.(string)
case []byte: // -- all cases go HERE!
fmt.Printf("[]byte\n")
record[columns[i]] = string(col.([]byte))
case time.Time:
// record[columns[i]] = col.(string)
}
}
}
s, _ := json.Marshal(record)
w.Write(s)
io.WriteString(w, "\n")
}
}
I also needed to dump database tables to json and here is how I achieved:
(different than another answer in this topic, everything is not string, thanks to this answer: https://stackoverflow.com/a/17885636/4124416, I could get integer fields correctly)
func getJSON(sqlString string) (string, error) {
rows, err := db.Query(sqlString)
if err != nil {
return "", err
}
defer rows.Close()
columns, err := rows.Columns()
if err != nil {
return "", err
}
count := len(columns)
tableData := make([]map[string]interface{}, 0)
values := make([]interface{}, count)
valuePtrs := make([]interface{}, count)
for rows.Next() {
for i := 0; i < count; i++ {
valuePtrs[i] = &values[i]
}
rows.Scan(valuePtrs...)
entry := make(map[string]interface{})
for i, col := range columns {
var v interface{}
val := values[i]
b, ok := val.([]byte)
if ok {
v = string(b)
} else {
v = val
}
entry[col] = v
}
tableData = append(tableData, entry)
}
jsonData, err := json.Marshal(tableData)
if err != nil {
return "", err
}
fmt.Println(string(jsonData))
return string(jsonData), nil
}
Here is a sample output:
[{"ID":0,"Text":"Zero"},{"ID":1,"Text":"One"},{"ID":2,"Text":"Two"}]
It is needed to use prepared statements to get the native types. MySQL has two protocols, one transmits everything as text, the other as the "real" type. And that binary protocol is only used when you use prepared statements. See https://github.com/go-sql-driver/mysql/issues/407
The function getJSON below is correct:
func getJSON(sqlString string) (string, error) {
stmt, err := db.Prepare(sqlString)
if err != nil {
return "", err
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil {
return "", err
}
defer rows.Close()
columns, err := rows.Columns()
if err != nil {
return "", err
}
tableData := make([]map[string]interface{}, 0)
count := len(columns)
values := make([]interface{}, count)
scanArgs := make([]interface{}, count)
for i := range values {
scanArgs[i] = &values[i]
}
for rows.Next() {
err := rows.Scan(scanArgs...)
if err != nil {
return "", err
}
entry := make(map[string]interface{})
for i, col := range columns {
v := values[i]
b, ok := v.([]byte)
if (ok) {
entry[col] = string(b)
} else {
entry[col] = v
}
}
tableData = append(tableData, entry)
}
jsonData, err := json.Marshal(tableData)
if err != nil {
return "", err
}
return string(jsonData), nil
}
There's not much you can do because the driver - database/sql interaction is pretty much a one way street and the driver can't help you with anything when the data is handed over to database/sql.
You could try your luck with http://godoc.org/github.com/arnehormann/sqlinternals/mysqlinternals
Query the database
Retrieve the Column slice with cols, err := mysqlinternals.Columns(rows)
Create a new var values := make([]interface{}, len(cols)) and iterate over cols
Get the closest matching Go type per column with refType, err := cols[i].ReflectGoType()
Create type placeholders with values[i] = reflect.Zero(refType).Interface()
rows.Next() and err = rows.Scan(values...). Don't recreate values, copy and reuse it.
I guess this will still be pretty slow, but you should be able to get somewhere with it.
If you encounter problems, please file an issue - I'll get to it as soon as I can.
I have a table named users inside practice_db database. I have mentioned the table structure with data in the following program that converts the users table into JSON format.
You can also check the source code at https://gist.github.com/hygull/1725442b0f121a5fc17b28e04796714d.
/**
{
"created_on": "26 may 2017",
"todos": [
"go get github.com/go-sql-driver/mysql",
"postman(optional)",
"browser(optional)",
],
"aim": "Reading fname column into []string(slice of strings)"
}
*/
/*
mysql> select * from users;
+----+-----------+----------+----------+-------------------------------+--------------+-------------------------------------------------------------------------------------------------+
| id | fname | lname | uname | email | contact | profile_pic |
+----+-----------+----------+----------+-------------------------------+--------------+-------------------------------------------------------------------------------------------------+
| 1 | Rishikesh | Agrawani | hygull | rishikesh0014051992#gmail.com | 917353787704 | https://cdn4.iconfinder.com/data/icons/rcons-user/32/user_group_users_accounts_contacts-512.png |
| 2 | Sandeep | E | sandeep | sandeepeswar8#gmail.com | 919739040038 | https://cdn4.iconfinder.com/data/icons/eldorado-user/40/user-512.png |
| 3 | Darshan | Sidar | darshan | sidardarshan#gmail.com | 917996917565 | https://cdn4.iconfinder.com/data/icons/rcons-user/32/child_boy-512.png |
| 4 | Surendra | Prajapat | surendra | surendrakgadwal#gmail.com | 918385894407 | https://cdn4.iconfinder.com/data/icons/rcons-user/32/account_male-512.png |
| 5 | Mukesh | Jakhar | mukesh | mjakhar.kjakhar#gmail.com | 919772254140 | https://cdn2.iconfinder.com/data/icons/rcons-user/32/male-circle-512.png |
+----+-----------+----------+----------+-------------------------------+--------------+-------------------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)
mysql>
*/
package main
import "log"
import "net/http"
import "encoding/json"
import (
_"github.com/go-sql-driver/mysql"
"database/sql"
)
func users(w http.ResponseWriter, r *http.Request) {
// db, err := sql.Open("mysql", "<username>:<password>#tcp(127.0.0.1:<port>)/<dbname>?charset=utf8" )
db, err := sql.Open("mysql", "hygull:admin#67#tcp(127.0.0.1:3306)/practice_db?charset=utf8")
w.Header().Set("Content-Type", "application/json")
if err != nil {
log.Fatal(err)
}
rows, err := db.Query("select id, fname, lname, uname, email, contact, profile_pic from users")
if err != nil {
log.Fatal(err)
}
type User struct {
Id int `json:"id"`
Fname string `json:"firstname"`
Lname string `json:"lastname"`
Uname string `json:"username"`
Email string `json:"email"`
Contact int `json:"contact"`
ProfilePic string `json:"profile_pic"`
}
var users []User
for rows.Next() {
var id, contact int
var fname string
var lname string
var uname, email, profile_pic string
rows.Scan(&id ,&fname, &lname, &uname, &email, &contact, &profile_pic)
users = append(users, User{id, fname, lname, uname, email, contact, &profile_pic })
}
usersBytes, _ := json.Marshal(&users)
w.Write(usersBytes)
db.Close()
}
func main() {
http.HandleFunc("/users/", users)
http.ListenAndServe(":8080", nil)
}
/* REQUSET
http://127.0.0.1:8080/users/
*/
/* RESPONSE
[
{
"id": 1,
"firstname": "Rishikesh",
"lastname": "Agrawani",
"username": "hygull",
"email": "rishikesh0014051992#gmail.com",
"contact": 917353787704,
"profile_pic": "https://cdn4.iconfinder.com/data/icons/rcons-user/32/user_group_users_accounts_contacts-512.png"
},
{
"id": 2,
"firstname": "Sandeep",
"lastname": "E",
"username": "sandeep",
"email": "sandeepeswar8#gmail.com",
"contact": 919739040038,
"profile_pic": "https://cdn4.iconfinder.com/data/icons/eldorado-user/40/user-512.png"
},
{
"id": 3,
"firstname": "Darshan",
"lastname": "Sidar",
"username": "darshan",
"email": "sidardarshan#gmail.com",
"contact": 917996917565,
"profile_pic": "https://cdn4.iconfinder.com/data/icons/rcons-user/32/child_boy-512.png"
},
{
"id": 4,
"firstname": "Surendra",
"lastname": "Prajapat",
"username": "surendra",
"email": "surendrakgadwal#gmail.com",
"contact": 918385894407,
"profile_pic": "https://cdn4.iconfinder.com/data/icons/rcons-user/32/account_male-512.png"
},
{
"id": 5,
"firstname": "Mukesh",
"lastname": "Jakhar",
"username": "mukesh",
"email": "mjakhar.kjakhar#gmail.com",
"contact": 919772254140,
"profile_pic": "https://cdn2.iconfinder.com/data/icons/rcons-user/32/male-circle-512.png"
}
]
*/
Based on the answers here, this is the most efficient code I could come up with. Note that this is outputting each row as a separate JSON array to save key name repetition.
// OutputJSONMysqlRowsStream outputs rows as a JSON array stream to save ram & output size due to key name repetition
func OutputJSONMysqlRowsStream(writer http.ResponseWriter, rows *sql.Rows) {
defer rows.Close()
columns, err := rows.Columns()
if err != nil {
OutputJSONError(writer, "Failed to get column names")
return
}
jsonColumns, err := json.Marshal(columns)
if err != nil {
OutputJSONError(writer, "Failed to encode json of column names")
return
}
writer.Header().Set("Content-Type", "application/cal-json-stream; charset=utf-8")
fmt.Fprintln(writer, "{\"status\": \"done\", \"data\":{ \"json_stream_fields\":"+string(jsonColumns)+"}}")
columnCount := len(columns)
rowDataHolder := make([]interface{}, columnCount)
rowDataHolderPointers := make([]interface{}, columnCount)
if err != nil {
log.Println(err)
}
for rows.Next() {
for i := 0; i < columnCount; i++ {
rowDataHolderPointers[i] = &rowDataHolder[i]
}
err := rows.Scan(rowDataHolderPointers...)
if err != nil {
log.Println(err)
} else {
for i, value := range rowDataHolder {
tempValue, ok := value.([]byte)
if ok {
rowDataHolder[i] = string(tempValue)
}
}
jsonEncoder := json.NewEncoder(writer)
err = jsonEncoder.Encode(rowDataHolder)
if err != nil {
log.Println(err)
}
}
}
}
you can dump the table into json just fine, however everything will be string :(
q := "select * from table"
debug("SQL: %s", q)
rows, err := db.Query(q)
checkError(err)
defer rows.Close()
columns, err := rows.Columns()
checkError(err)
scanArgs := make([]interface{}, len(columns))
values := make([]interface{}, len(columns))
for i := range values {
scanArgs[i] = &values[i]
}
for rows.Next() {
err = rows.Scan(scanArgs...)
checkError(err)
record := make(map[string]interface{})
for i, col := range values {
if col != nil {
record[columns[i]] = fmt.Sprintf("%s", string(col.([]byte)))
}
}
s, _ := json.Marshal(record)
fmt.Printf("%s\n", s)
}