Inserting data to mysql database from function . api - mysql

Highlevel:my program gets a long URL and makes it shorter(like tinyurl). But i have problem passing Long URL variable and shortURL variable from function to a mySQL database. I have tried looking it up on internet but noluck and information im getting is not close to what i have. im only posting some parts of my code the full code will be in playground
var db *sql.DB //global variable
func main(){
var db, err = sql.Open("mysql", dsn())
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Printf("Connection established to MYSQL server\n%s\n", dsn())
}
defer db.Close()
linkList = map[string]string{}
http.HandleFunc("/link", addLink)
http.HandleFunc("/hpe/", getLink)
http.HandleFunc("/", Home)
// Flags to pass string ip or port to WEB app
ip := flag.String("i", "0.0.0.0", "")
port := flag.String("p", "8080", "")
flag.Parse()
fmt.Printf("Web application listening on %s \n", net.JoinHostPort(*ip, *port))
log.Fatal(http.ListenAndServe(net.JoinHostPort(*ip, *port), nil))
}
function that creates short url. Every time this func is called it produces link
func addLink(w http.ResponseWriter, r *http.Request) {
log.Println("Add Link")
key, ok := r.URL.Query()["ik"]
if ok {
if !validLink(key[0]) {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "Could not create shortlink need absolute path link.")
return
}
log.Println(key)
if _, ok := linkList[key[0]]; !ok {
genString := randomString(5)
linkList[genString] = key[0]
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusAccepted)
linkString := fmt.Sprintf("hpe/%s", genString, genString)
fmt.Fprintf(w, "Added shortlink\n")
fmt.Fprintf(w, linkString)
return
// database function
defer db.Close()
s:
result, err := db.Exec("insert into Url (LongUrl, ShortUrl) value(?,?);",genString,linkString)
if err != nil {
fmt.Print(err.Error())
} else {
_,err:=result.LastInsertId()
}
}
w.WriteHeader(http.StatusConflict)
fmt.Fprintf(w, "Already have this link")
return
}
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "Failed to add link")
return
}
func getLink(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
log.Println("Get Link:", path)
pathArgs := strings.Split(path, "/")
if len(pathArgs[2]) < 1 {
w.WriteHeader(http.StatusNotFound)
http.Redirect(w, r, "0.0.0.0:8080", http.StatusTemporaryRedirect)
return
}
log.Printf("Redirected to: %s", linkList[pathArgs[2]])
http.Redirect(w, r, linkList[pathArgs[2]], http.StatusTemporaryRedirect)
//fmt.Printf("all %s", linkList)
return
}
My expectation is when func addlink gets called the info that generated from long and short url gets put into database like in the code.

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

Golang json marshal and encoding give weird output

I am trying to customise error message for my db query . Following is what I am doing first I create struct Errormessage . Next if there is error in db.query I do this marshaling then encoding and return. But I end up getting this output "e30=" on my postman testing. What could be wrong I check and followed few examples are showing this mechanism ?
error1 := Errormessage{"Error in select"}
error1_enc,errEn := json.Marshal(error1)
if errEn != nil {
// if error is not nil
// print error
fmt.Println(errEn)
}
json.NewEncoder(w).Encode(error1_enc)
return
/
/ declaring a struct
type Errormessage struct{
// defining struct variables
errormessage string
}
func checkExistUser(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println("File Name :", r.FormValue("email"))
result, err := db.Query("SELECT * from userDetailsss")
if err != nil {
//http.Error(w, err, 500)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(400)
fmt.Println(err)
error1 := Errormessage{"Error in select"}
error1_enc,errEn := json.Marshal(error1)
if errEn != nil {
// if error is not nil
// print error
fmt.Println(errEn)
}
json.NewEncoder(w).Encode(error1_enc)
return
//panic(err.Error())
}
// This part is how my db is defined and opened
var db *sql.DB
var err error
func main() {
db, err = sql.Open("mysql", "******##tcp(127.0.0.1:3306)/****")
if err != nil {
panic(err.Error())
}
defer db.Close()
router := mux.NewRouter()
router.HandleFunc("/", DoHealthCheck).Methods("POST")
router.HandleFunc("/checkExistUser", checkExistUser).Methods("POST")
log.Fatal(http.ListenAndServe(":8080", router))
}
There are two issues with your code:
You are json encoding the already json encoded error. This means that you are json encoding raw json bytes, which is the reason for the weird output.
Your Errormessage struct's field is unexported. Unexported fields will not be encoded by the encoding/json package.
To fix #1 you can do:
func checkExistUser(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println("File Name :", r.FormValue("email"))
result, err := db.Query("SELECT * from userDetailsss")
if err != nil {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(400)
// use only Encode, no need to call json.Marshal
if err := json.NewEncoder(w).Encode(Errormessage{"Error in select"}); err != nil {
log.Println("failed to send reposnse:", err)
}
return
}
// ...
}
To fix #2 you can do:
type Errormessage struct {
// export the field, i.e. change it to start with an upper case letter
Errormessage string `json:"errormessage"`
}

How to get values from a variable of type *sql.Rows in the view?

In posts table, there are attributes like title, content.
I can get data of type *sql.Rows and pass them to the view by
posts, err := db.Query("SELECT id, title FROM posts WHERE id = 1")
and
err = tpl.ExecuteTemplate(w, "index.gohtml", posts)
but I couldn't display the title value in the view. Here is my code.
index.go
package main
import (
"net/http"
"fmt"
"log"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func index(w http.ResponseWriter, r *http.Request) {
db, err := sql.Open("mysql", "root:****#/database")
if err != nil {
panic(err.Error())
}
defer db.Close()
posts, err := db.Query("SELECT id, title FROM posts WHERE id = 1")
var id int
var title string
for posts.Next() {
err = posts.Scan(&id, &title)
if err != nil {
panic(err.Error())
}
}
fmt.Println(posts)
defer posts.Close()
err = tpl.ExecuteTemplate(w, "index.gohtml", posts)
if err != nil {
log.Println(err)
}
}
index.gohtml
<h1>Awesome Posts</h1>
{{$posts := .}}
<p>{{$posts}}</p>
There are a few mistakes in your code and I think you have misunderstood how to extract data using the sql package.
As Flimzy said in the comments, you should pass a proper context struct which contains your ID and Title values somewhere.
If you check the docs for sql.Rows you will see how to extract the data at each of the rows from your query...and in fact you already know how to get the rows and column values - by using the Next() and Scan() methods. But this should not be done by code in the HTML template, it should store the results in some variable which is passed to the template.
Quick Answer
A quick answer to your question would be to change how you pass the values into the template and amend the template. Seeing as you declare id and title variables you should pass them to the template:
err = tpl.ExecuteTemplate(w, "index.gohtml", map[string]interface{}{"ID": id,"Title": title})
if err != nil {
log.Println(err)
}
<h1>Awesome Posts</h1>
<p>{{.ID}} - {{.Title}}</p>
Having a Post model
A better solution would be to have a struct which holds all of the properties of the post, and use this to Scan into.
type Post struct{
ID int
Title string
}
...
var p Post
...
_ = rows.Scan(&p)
However, there is another problem with the way you are storing the results of the query. You are using db.Query to return a single row - This is an assumption as you have WHERE ID=1. If you expect only one post to be returned then use the QueryRow method: (N.B. you can chain on the Scan method for simplicity)
var p Post
// error handling removed for brevity
_ = db.QueryRow("SELECT id, title FROM posts WHERE id = 1").Scan(&p)
_ = tpl.ExecuteTemplate(w, "index.gohtml", p)
If, however, you are expecting to retrieve multiple posts (and you were just adding the where clause for simplicity), then you need to Scan into a Post struct, and append into a slice of Posts.
rows, _ := db.Query("SELECT id, title FROM posts")
defer rows.Close()
var posts []Post
for rows.Next() {
var p Post
_ = posts.Scan(&id, &p) // you should handle error here.
posts = append(posts, p)
}
if err = tpl.ExecuteTemplate(w, "index.gohtml", posts); err!=nil{
log.Println(err)
}
Other considerations
You should not be creating a connection to the DB within the HTTP handler. One way is to have a global variable which holds the connection. A struct with embedded connection can work and/or it is possible to abstract away the connection into a package as well.
/db/db.go
package db
import (
"database/sql"
// MYSQL driver
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
// Open handles the opening of the DB
func Open(connstr string) (err error) {
db, err = sql.Open("mysql", connstr)
if err != nil {
return err
}
return nil
}
// Close handles the closing of the DB
func Close() error {
return db.Close()
}
/db/posts.go
package db
// Post model
type Post struct {
ID uint
Title string
Body string
}
const (
getPosts = `SELECT id, title, body FROM posts`
getAPost = `SELECT id, title, body FROM posts WHERE id=?`
)
// GetPosts will return all posts from the DB
func GetPosts() ([]Post, error) {
rows, err := db.Query(getPosts)
if err != nil {
return nil, err
}
var posts []Post
for rows.Next() {
var p Post
if err := rows.Scan(&p.ID, &p.Title, &p.Body); err != nil {
return nil, err
}
posts = append(posts, p)
}
return posts, nil
}
// GetPost will return single post identified by ID from the DB
func GetPost(id uint) (Post, error) {
var p Post
if err := db.QueryRow(getAPost, id).Scan(&p.ID, &p.Title, &p.Body); err != nil {
return p, err
}
return p, nil
}
main.go
import (
"chilledoj/sopost/db" // this is the absolute path to the db folder
"html/template"
"log"
"net/http"
"strconv"
"flag"
"github.com/gorilla/mux"
)
var dbconn string
func init() {
flag.StringVar(&dbconn, "dbconn", "", "MYSQL DB Connection string")
flag.Parse()
}
func main() {
if dbconn == "" {
log.Fatal("DB Connection string not set")
}
if err := db.Open(dbconn); err != nil {
log.Fatal(err)
}
defer db.Close()
r := mux.NewRouter()
r.HandleFunc("/", indexHandler())
r.HandleFunc("/posts", postsHandler())
r.HandleFunc("/posts/{id}", postHandler())
if err := http.ListenAndServe(":8080", r); err != nil {
log.Panic(err)
}
}
var indexHandler = func() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`<h1>Welcome</h1>Posts`))
}
}
var postsHandler = func() http.HandlerFunc {
tmpl, err := template.New("posts").Parse(`<h1>Awesome Posts</h1>
<ul>{{range .}}
<li>{{.Title}}</li>
{{end}}</ul>
<hr/>
Home`)
if err != nil {
log.Panic(err)
}
return func(w http.ResponseWriter, r *http.Request) {
posts, err := db.GetPosts()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
err = tmpl.Execute(w, posts)
if err != nil {
log.Printf("There was a template Error.\n%v\n", err)
}
}
}
var postHandler = func() http.HandlerFunc {
tmpl, err := template.New("posts").Parse(`<h1>Awesome Posts</h1>
<h2>{{.Title}}</h2>
<p>{{.Body}}</p>
<hr/>
Home
Posts`)
if err != nil {
log.Panic(err)
}
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, err := strconv.ParseInt(vars["id"], 10, 32)
if err != nil {
http.NotFound(w, r)
return
}
post, err := db.GetPost(uint(id))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
tmpl.Execute(w, post)
}
}
Run the above using
go run main.go -dbconn [dbuser]:[dbpass]#/[dbname]?parseTime=true
Another way is to use dependency injection and have a function take in a db connection but return an http.HandlerFunc. e.g.
var indexHandler = function (db *sql.DB) http.HandlerFunc{
return function(w http.ResponseWriter, r *http.Request){
// now have access to db
}
}
http.HandleFunc("/posts", indexHandler())

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

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)
}

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)
}
}