Skip to content

Instantly share code, notes, and snippets.

@innomon
Created July 14, 2024 12:07
Show Gist options
  • Save innomon/b2a358126e121c847415f81274651e27 to your computer and use it in GitHub Desktop.
Save innomon/b2a358126e121c847415f81274651e27 to your computer and use it in GitHub Desktop.
PoC of HTML form submit with golang backend

chatGPT generated, form submission code

Init Database

Dolt is used as the database

innomon@raspberrypi:~/sandbox/submit-form-poc $ dolt init
Successfully initialized dolt data repository.

Run the server

dolt sql-server

open a mysql client, BeeKeeper and create the dat table.

CREATE DATABASE productdb;

USE productdb;

CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    sku VARCHAR(255) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    priceCurrency VARCHAR(10) NOT NULL,
    brand VARCHAR(255),
    category VARCHAR(255),
    image LONGTEXT
);

Go program install

 innomon@raspberrypi:~/sandbox/submit-form-poc $ go mod init main
 go: creating new go.mod: module main
 go: to add module requirements and sums:
go mod tidy
innomon@raspberrypi:~/sandbox/submit-form-poc $ go mod tidy

Place the index.html inside the static sub-directory.

run the server: go run main.go

serves at localhost:8080

open the browser and point to http://localhost:8080/

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product Input Form</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 600px;
}
h2 {
text-align: center;
color: #333;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
color: #333;
}
.form-group input, .form-group textarea, .form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
color: #333;
}
.form-group textarea {
resize: vertical;
height: 100px;
}
.form-group button {
background-color: #28a745;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
.form-group button:hover {
background-color: #218838;
}
#imagePreview {
width: 100%;
max-width: 200px;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<h2>Product Input Form</h2>
<form id="productForm">
<div class="form-group">
<label for="productName">Product Name</label>
<input type="text" id="productName" name="name" required>
</div>
<div class="form-group">
<label for="productDescription">Description</label>
<textarea id="productDescription" name="description" required></textarea>
</div>
<div class="form-group">
<label for="productSKU">SKU</label>
<input type="text" id="productSKU" name="sku" required>
</div>
<div class="form-group">
<label for="productPrice">Price</label>
<input type="number" id="productPrice" name="price" step="0.01" required>
</div>
<div class="form-group">
<label for="productCurrency">Currency</label>
<select id="productCurrency" name="priceCurrency" required>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
<option value="GBP">GBP</option>
<option value="JPY">JPY</option>
</select>
</div>
<div class="form-group">
<label for="productBrand">Brand</label>
<input type="text" id="productBrand" name="brand">
</div>
<div class="form-group">
<label for="productCategory">Category</label>
<input type="text" id="productCategory" name="category">
</div>
<div class="form-group">
<label for="productImage">Image URL</label>
<input type="url" id="productImage" name="image">
</div>
<div class="form-group">
<label for="uploadImage">Upload Image</label>
<input type="file" id="uploadImage" accept="image/*">
<img id="imagePreview" src="" alt="Image Preview">
</div>
<div class="form-group">
<button type="button" onclick="submitForm()">Submit</button>
</div>
</form>
</div>
<script>
document.getElementById('uploadImage').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
document.getElementById('imagePreview').src = e.target.result;
document.getElementById('productImage').value = e.target.result;
};
reader.readAsDataURL(file);
}
});
function submitForm() {
const form = document.getElementById('productForm');
const formData = new FormData(form);
const jsonData = {};
formData.forEach((value, key) => {
jsonData[key] = value;
});
fetch('http://localhost:8080/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(jsonData)
})
.then(response => {
if (response.status === 201) {
alert('Product created successfully');
} else {
response.text().then(text => { alert('Error: ' + text); });
}
})
.catch(error => {
console.error('Error:', error);
});
}
</script>
</body>
</html>
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"time"
// "path/filepath"
u "net/http/httputil"
_ "github.com/go-sql-driver/mysql"
)
type Product struct {
Name string `json:"name"`
Description string `json:"description"`
SKU string `json:"sku"`
Price string `json:"price"`
PriceCurrency string `json:"priceCurrency"`
Brand string `json:"brand"`
Category string `json:"category"`
Image string `json:"image"`
}
var db *sql.DB
func initDB() {
var err error
dsn := "root:@tcp(127.0.0.1:3306)/productdb"
db, err = sql.Open("mysql", dsn)
if err != nil {
log.Fatalf("Error opening database: %v", err)
}
if err = db.Ping(); err != nil {
log.Fatalf("Error connecting to the database: %v", err)
}
fmt.Println("Successfully connected to the database")
}
func main() {
initDB()
// Serve static files from the "static" directory
fs := http.FileServer(http.Dir("static"))
http.Handle("/", fs)
http.HandleFunc("/submit", handleFormSubmit)
//http.HandleFunc("/submit", dumper)
fmt.Println("Server is running on port 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handleFormSubmit(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
return
}
var product Product
decoder := json.NewDecoder(r.Body)
//fmt.Println(r.Body)
if err := decoder.Decode(&product); err != nil {
http.Error(w, "Error decoding JSON"+err.Error(), http.StatusBadRequest)
return
}
query := `INSERT INTO products (name, description, sku, price, priceCurrency, brand, category, image)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
price, err := strconv.ParseFloat(product.Price, 64)
if err != nil {
http.Error(w, "Error convering price into the database"+err.Error(), http.StatusInternalServerError)
return
}
fmt.Println("image text len:", len(product.Image))
_, err = db.Exec(query, product.Name, product.Description, product.SKU, price, product.PriceCurrency, product.Brand, product.Category, product.Image)
if err != nil {
http.Error(w, "Error inserting data into the database"+err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, "Product created successfully")
}
func dumper(w http.ResponseWriter, r *http.Request) {
b, err := u.DumpRequest(r, true)
w.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
} else {
w.WriteHeader(http.StatusOK)
w.Write(b)
w.Write([]byte("\nRemote Address:[" + r.RemoteAddr + "]\n"))
now := time.Now()
tmj, err := now.MarshalJSON()
if err == nil {
w.Write(tmj)
} else {
w.Write([]byte(err.Error()))
}
w.Write([]byte("\n"))
if r.Body != nil {
var b []byte = make([]byte, r.ContentLength)
if _, err := r.Body.Read(b); err == nil {
w.Write([]byte("\n-----------------BODY--------"))
w.Write(b)
w.Write([]byte("\n-----------------BODY--------"))
} else {
w.Write([]byte(err.Error()))
}
} else {
w.Write([]byte("\n no Body received"))
}
}
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment