I currently have a splash page up and running through Google's App Engine. As of now it is just a page that asks users for their email and name, in order to build an email list. I wanted to store the information on cloud sql, but I cannot seem to get it to work on the live site. As of now I am using MySQLWorkbench to successfully connect to the database on cloud sql and I can input data and submit it which successfully fills in the information to the database on the cloud. I do not receive any connection errors and it works as intended locally on localhost:8080/. I then deployed my changes to app engine and navigate to the site, fill in the information, and hit submit the page hangs and eventually returns a 500 error on my Insert method. This is my first time working with DB on a live site so I cannot understand what the issue is moving from localhost to the live site.
main.go:
import (
"database/sql"
"fmt"
"html/template"
"log"
"net/http"
"os"
"path/filepath"
"strings"
_ "github.com/go-sql-driver/mysql"
)
// Page type
type Page struct {
Title string
}
type emailListUser struct {
ID int
Name string
email string
}
// Connect to DB
func dbConn() (db *sql.DB) {
dbDriver := "mysql"
dbUser := "jmcarthur"
dbPass := "my_password"
dbName := "tcp(ipFromGoogle:port)/tableName" // Also tried ipFromGoogle:port and ipFromGoogle
db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@"+dbName)
if err != nil {
log.Println("Failed connection")
}
return db
}
// Handlers
func emailListHandler(w http.ResponseWriter, r *http.Request) {
tpl.ExecuteTemplate(w, "emailList", &Page{Title: "Welcome to My Site"})
}
func main() {
http.HandleFunc("/", emailListHandler)
http.HandleFunc("/insert", Insert)
fs := http.FileServer(http.Dir("static"))
http.Handle("/css/", fs)
http.Handle("/fonts/", fs)
http.Handle("/img/", fs)
http.Handle("/templates/", fs)
fmt.Println(http.ListenAndServe(":8080", nil))
}
var tpl = func() *template.Template {
t := template.New("")
err := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
if strings.Contains(path, ".html") {
fmt.Println(path)
_, err = t.ParseFiles(path)
if err != nil {
fmt.Println(err)
}
}
return err
})
if err != nil {
panic(err)
}
return t
}()
// Insert function
func Insert(w http.ResponseWriter, r *http.Request) {
db := dbConn()
if r.Method == "POST" {
email := r.FormValue("email")
name := r.FormValue("name")
insForm, err := db.Prepare("INSERT INTO emailList(email_address, name) VALUES(?,?)")
if err != nil {
panic(err.Error())
}
insForm.Exec(email, name)
log.Println("INSERT: Email: " + email + " | Name: " + name)
}
defer db.Close()
http.Redirect(w, r, "/", 301)
}
/* CREATE TABLE tableName(
email_id INT NOT NULL AUTO_INCREMENT,
email_address VARCHAR(320) NOT NULL,
name VARCHAR(150) NOT NULL,
PRIMARY KEY (email_id)
); */
emailList.html
{{define "emailList"}}
<!DOCTYPE html>
<html lang="en">
{{template "header" .}}
<body id="emailListBody" class="text-center">
<div id="emailListContainer" class="col-12 text-center">
<img src="./img/picture.png" height="250px" width="250px">
<h1 class="text-center" id="slogan">slogan</h1>
<div id="formDiv" class="text-center">
<form method="POST" action="insert">
<label for="email" class="col-12" id="emailLabel">Email:</label>
<input type="email" required placeholder="[email protected]" id="email" name="email">
<label for="name" class="col-12" id="nameLabel">Name:</label>
<input type="text" required placeholder="John Doe" id="name" name="name">
<div class="col">
<button class="btn btn-default" id="submitButton">SUBMIT</button>
</div>
</form>
</div>
</div>
{{template "footer" .}}
{{end}}
Tree:
.
├── app.yaml
├── cloud_sql_proxy
├── main.go
└── static
├── css
│ └── main.css
├── emailList.html
├── fonts
│ ├── EuroStyle\ Normal.ttf
│ ├── EurostileBold.ttf
│ └── ethnocentric\ rg.ttf
├── img
│ ├── picture.png
├── js
└── templates
├── footer.html
└── header.html
As I said I can successfully get it working locally, but cannot for the life of me get it to work on the live site. I have ensured that my IP is whitelisted, I tried connecting with the IP in many different ways with and without the port (as can be seen in main.go), but every time I get POST mysite [HTTP/2 500 Internal Server Error 1857ms]
. I believe my confusion is with cloud sql and allowing any IP to send data to the database, but I could be completely wrong. Please help, thank you!!
The issue was with my connection function. The solution that ended up working is shown below.
Note: projectID = name of your google cloud project
cloudSQLInstace = name of the instance you created for cloud SQL
my_username and my_password come from created user under SQL -> Users
func dbConn() (db *sql.DB) {
dbDriver := "mysql"
dbUser := "my_username"
dbPass := "my_password"
dbInstance := "projectID:us-central1:cloudSQLInstace"
dbName := "emailList"
db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@unix(/cloudsql/"+dbInstance+")/"+dbName)
if err != nil {
log.Fatalf("Failed connection")
}
return db
}