I need help on this Golang web application using mysql as database - mysql

I am new to Golang and had been following some tutorials and I want to put into practice what I have learned to create a website
This is the main.go file
package main
import (
"html/template"
"net/http"
"log"
"database/sql"
_"github.com/go-sql-driver/mysql"
)
//Fetch all templates
var templates, templatesErr = template.ParseGlob("templates/*")
func main() {
PORT := ":9000"
log.Println("Listening to port", PORT)
http.HandleFunc("/", root)
http.HandleFunc("/facilities", allFacilities)
http.ListenAndServe(PORT, nil)
}
func root(w http.ResponseWriter, r *http.Request) {
rootData := make(map[string]string)
rootData["page_title"] = "iSpace Open Data"
rootData["body"] = ""
templates.ExecuteTemplate(w, "index.html", rootData)
}
type facility struct{
FacilityName string
Type string
}
func allFacilities(w http.ResponseWriter, r *http.Request){
db, err := sql.Open("mysql", "root:08swanzy#tcp(127.0.0.1:3306)/iod")
if err !=nil{
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("Select FacilityName, Type from health_facilities ")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
fac := facility{}
facilities := []facility{}
for rows.Next(){
var FacilityName, Type string
rows.Scan(&FacilityName, &Type)
fac.FacilityName= FacilityName
fac.Type= Type
facilities = append(facilities, fac)
}
templates.ExecuteTemplate(w, "facilities.html", facilities)
}
This uses html files in templates folder for the view. But I keep on getting runtime error saying it has pointer dereference. I need help please.

Tried your code and got the same error. It happened on this line:
templates.ExecuteTemplate(w, "index.html", rootData)
The problem is that your templates are not loaded correctly. I moved template parsing to the main function and it works. Here the relevant code snippet:
//Fetch all templates
var (
templates *template.Template
)
func main() {
var err error
templates, err = template.ParseGlob("templates/*")
if err != nil {
panic(err)
}
PORT := ":9000"
log.Println("Listening to port", PORT)
http.HandleFunc("/", root)
http.HandleFunc("/facilities", allFacilities)
http.ListenAndServe(PORT, nil)
}

Related

How to set up web server to perform POST Request in Go?

I want to set up a web server to perform a POST request. How does the post request get executed with the code below since only HandleFunc and ListenAndServe are defined in main function?
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
func post(w http.ResponseWriter, r *http.Request) {
const myurl string = "http://localhost:8000/"
request := strings.NewReader(`
{
"Name":"Tom",
"Age":"20"
}
`)
response, err := http.Post(myurl, "application/json", request)
content, err := ioutil.ReadAll(response.Body)
if err != nil {
panic(err)
}
fmt.Println(string(content))
defer response.Body.Close()
}
func main() {
http.HandleFunc("/", post)
log.Fatal(http.ListenAndServe(":8000", nil))
}
Here is a basic example of how you could go about it. I am using the same program to run both, the server and the client. This is just for demonstration purposes. You can of course make them separate programs.
// use struct to represent the data
// to recieve and send
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
// run the example
func main() {
// start the server in a goroutine
go server()
// wait 1 second to give the server time to start
time.Sleep(time.Second)
// make a post request
if err := client(); err != nil {
fmt.Println(err)
}
}
// basic web server to receive a request and
// decode the body into a user struct
func server() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
user := &Person{}
err := json.NewDecoder(r.Body).Decode(user)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Println("got user:", user)
w.WriteHeader(http.StatusCreated)
})
if err := http.ListenAndServe(":8080", nil); err != http.ErrServerClosed {
panic(err)
}
}
// a simple client that posts a user to the server
func client() error {
user := &Person{
Name: "John",
Age: 30,
}
b := new(bytes.Buffer)
err := json.NewEncoder(b).Encode(user)
if err != nil {
return err
}
resp, err := http.Post("http://localhost:8080/", "application/json", b)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Println(resp.Status)
return nil
}
Here is the working example: https://go.dev/play/p/34GT04jy_uA

How to insert csv file using one command in clickhouse using golang

Is there a way to insert csv file using this go library https://github.com/ClickHouse/clickhouse-go in one command (without reading csv and iterating through the content.). If there is a way can you provide me with the example.
if not how can we convert this system command and write it in golang using os/exec library.
cat /home/srijan/employee.csv | clickhouse-client --query="INSERT INTO test1 FORMAT CSV"
It's impossible with that go library. You can use http api https://clickhouse.com/docs/en/interfaces/http/ and any http go client
for example
package main
import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
)
func compress(data io.Reader) io.Reader {
pr, pw := io.Pipe()
gw, err := gzip.NewWriterLevel(pw, int(3))
if err != nil {
panic(err)
}
go func() {
_, _ = io.Copy(gw, data)
gw.Close()
pw.Close()
}()
return pr
}
func main() {
p, err := url.Parse("http://localhost:8123/")
if err != nil {
panic(err)
}
q := p.Query()
q.Set("query", "INSERT INTO test1 FORMAT CSV")
p.RawQuery = q.Encode()
queryUrl := p.String()
var req *http.Request
req, err = http.NewRequest("POST", queryUrl, compress(os.Stdin))
req.Header.Add("Content-Encoding", "gzip")
if err != nil {
panic(err)
}
client := &http.Client{
Transport: &http.Transport{DisableKeepAlives: true},
}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
panic(fmt.Errorf("clickhouse response status %d: %s", resp.StatusCode, string(body)))
}
}

Blank page without errors when using post in go code

I'm new to Go programming and I am writing a function to post into an alternate key as the primary key auto-increments using Go, Mysql, and template.HTML package.
After troubleshooting for the last few days I am loading a blank html page.
Any suggestions on best practice or ways I should troubleshoot in the future would be so appreciated.
Thank you so much for any help you are willing to offer!
I used linters and formatters to ensure that the code is correctly formatted, used print statements, and rebuilt the function and html content from scratch to narrow it down.
HTTP handler
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"text/template"
_ "github.com/go-sql-driver/mysql"
)
type watchInfo struct {
ID int
Brand string
}
var (
tpl *template.Template
// cnn, err = sql.Open("mysql", "root:root#tcp(db:3306)/appdb")
)
//function to connect to db
func dbConn() (db *sql.DB) {
dbDriver := "mysql"
dbUser := "root"
dbPass := "root"
dbName := "appdb"
db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"#tcp"+"(db:3306)/"+dbName)
if err != nil {
fmt.Println("dbConn not work")
}
return db
}
func init() {
tpl = template.Must(template.ParseGlob("/go/templates/*"))
}
func main() {
http.HandleFunc("/", index)
http.HandleFunc("/upload", uploadWatchInfo)
http.ListenAndServe(":8080", nil)
}
//This function get watch id and brand using getWatch function and passes them to the gohtml template file
func index(w http.ResponseWriter, r *http.Request) {
db := dbConn()
defer db.Close()
scanWatches, err := db.Query("SELECT * FROM watches order by id")
if err != nil {
log.Fatal(err)
}
err = db.Ping()
if err != nil {
fmt.Println(err.Error())
}
watch := watchInfo{}
watchSlice := []watchInfo{}
for scanWatches.Next() {
var id int
var brand string
err = scanWatches.Scan(&id, &brand)
if err != nil {
fmt.Println("sW.Scan didn't work")
}
watch.ID = id
watch.Brand = brand
watchSlice = append(watchSlice, watch)
}
tpl.ExecuteTemplate(w, "pic.gohtml", watchSlice)
}
func uploadWatchInfo(w http.ResponseWriter, r *http.Request) {
db := dbConn()
defer db.Close()
if r.Method == "POST" {
brand := r.FormValue("brand")
insForm, err := db.Prepare("INSERT INTO watches(brand) VALUES(?)")
if err != nil {
panic(err.Error)
}
insForm.Exec(brand)
err = tpl.ExecuteTemplate(w, "upload.gohtml", watchInfo{Brand: brand})
if err != nil {
panic(err.Error)
}
}
}
//this is handling an error and can be called in other page functions
func HandleError(w http.ResponseWriter, err error) {
if err != nil {
fmt.Println("Index did not work. error in index")
}
}
HTML Template
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Upload page</title>
</head>
<body>
<h1>upload page</h1>
<form method="POST" action="insert">
<label> brand </label><input type="text" name="brand"/><br />
<input type="submit" value="Save brand"/>
</form>
Index
</body>
</html>
I Expect my handler to insert the string value into the database and print the confirmation in the terminal.

Printing decoded JSON in Golang

I am very new to Go / programming in general - having just picked it up whilst messing about creating my own crypto currency portfolio web site.
I am struggling printing to the web server output. If I used Printf - it prints to console but as soon as I use Fprintf to print to the web app, I get a number of errors which I can't seem to solve.
Could someone walk me through it?
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type Obsidian []struct {
PriceUsd string `json:"price_usd"`
PriceBtc string `json:"price_btc"`
}
func webserver(w http.ResponseWriter, r *http.Request) {
url := "https://api.coinmarketcap.com/v1/ticker/obsidian/"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal("NewRequest: ", err)
return
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal("Do: ", err)
return
}
defer resp.Body.Close()
var record Obsidian
if err := json.NewDecoder(resp.Body).Decode(&record); err != nil {
log.Println(err)
}
fmt.Printf("%+v", record)
}
func main() {
http.HandleFunc("/test", webserver)
http.ListenAndServe(":8001", nil)
}
I have tried to replace:
fmt.Printf("%+v", record)
with:
fmt.Fprintf("%+v", record)
and receive the following errors:
./test.go:54:21: cannot use "%+v" (type string) as type io.Writer in argument to fmt.Fprintf:
string does not implement io.Writer (missing Write method)
./test.go:54:21: cannot use record (type Obsidian) as type string in argument to fmt.Fprintf
Thanks to #MiloChrisstiansen
fmt.Fprintf(w, "%+v", record)
You could also use
w.Write([]byte(record))

list bucket content by name GCS go

I'm trying to read the content of a bucket on Google Cloud Storage using GO.
I'm able to do that, but is is very slow.
The content of the bucket is like this:
bucket name
-> folders with alphanumeric characters
----> 5 files into each of the folder
--------> each file has a json array inside
what I want to do is to inspect the content of the jsons files for all the folders in the bucket and look for a specific value. The following code work, but it is very slow:
package backend
import (
"encoding/json"
"fmt"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/appengine"
"google.golang.org/appengine/file"
"google.golang.org/appengine/urlfetch"
"google.golang.org/cloud"
"google.golang.org/cloud/storage"
"io"
"io/ioutil"
"net/http"
)
var bucket = "bucket_Name"
type jsonStruct struct {
Gender string `json:"gender"`
Age string `json:"age"`
ID string `json:"id"`
Done int `json:"done"`
}
type saveData struct {
c context.Context
r *http.Request //http response
w http.ResponseWriter //http writer
ctx context.Context
cleanUp []string // cleanUp is a list of filenames that need cleaning up at the end of the saving.
failed bool // failed indicates that one or more of the saving steps failed.
}
func init() {
http.HandleFunc("/", handleStatic)
http.HandleFunc("/listBuckets", listBuckets)
}
func handleStatic(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache")
http.ServeFile(w, r, "static/"+r.URL.Path)
}
func listBuckets(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
if bucket == "" {
var err error
if bucket, err = file.DefaultBucketName(c); err != nil {
// log.Errorf(c, "failed to get default GCS bucket name: %v", err)
return
}
}
hc := &http.Client{
Transport: &oauth2.Transport{
Source: google.AppEngineTokenSource(c, storage.ScopeFullControl),
Base: &urlfetch.Transport{Context: c},
},
}
ctx := cloud.NewContext(appengine.AppID(c), hc)
// structure to holds information needed to run the various saving functions
d := &saveData{
c: c,
r: r,
w: w,
ctx: ctx,
}
d.listBucket(bucket)
}
func (d *saveData) errorf(format string, args ...interface{}) {
d.failed = true
// log.Errorf(d.c, format, args...)
}
func (d *saveData) listBucket(bucket string) {
io.WriteString(d.w, "\nListbucket result:\n")
query := &storage.Query{}
for query != nil {
objs, err := storage.ListObjects(d.ctx, bucket, query)
if err != nil {
d.errorf("listBucket: unable to list bucket %q: %v", bucket, err)
return
}
query = objs.Next
for _, obj := range objs.Results {
d.readFile(obj.Name)
}
}
}
func (d *saveData) readFile(fileName string) {
rc, err := storage.NewReader(d.ctx, bucket, fileName)
if err != nil {
d.errorf("readFile: unable to open file from bucket %q, file %q: %v", bucket, fileName, err)
return
}
defer rc.Close()
slurp, err := ioutil.ReadAll(rc)
if err != nil {
d.errorf("readFile: unable to read data from bucket %q, file %q: %v", bucket, fileName, err)
return
}
var userDetails jsonStruct
err1 := json.Unmarshal(slurp, &userDetails)
if err1 != nil {
d.errorf("readFile: %v", err1)
return
}
fmt.Fprintf(d.w, "done is: %v\n", userDetails.Done)
}
Basically now I'm reading the folder name from the bucket and then I read the content using the folder name. It would be possible to cache all the bucket content in a go variable and then work on that variable instead of read the bucket for each folder?
I really need this to be faster because I need to present the result back in real time.
Thanks a lot
See below a simple Go sample code to list the bucket content on Google Cloud Storage:
package main
import (
"context"
"fmt"
"log"
"os"
"cloud.google.com/go/storage"
"google.golang.org/api/iterator"
)
func main() {
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS",
"C:\\Users\\Shubham Snehi\\Downloads\\awacs-dev-160bf0e57dc1.json")
ctx := context.Background()
client, err := storage.NewClient(ctx)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
// Sets the name for the new bucket.
bucketName := "balatestawacs"
// Creates a Bucket instance.
bucket := client.Bucket(bucketName)
it := bucket.Objects(ctx, nil)
for {
attrs, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
panic(err)
}
fmt.Println(attrs.Owner)
}
}