About Go for Web development
Using Go for web development is not that common. But my personal experience is that Go outperforms Wordpress, Drupal, PHP and Angular several times. And combining Javascript in the browser and Go on the server makes it a perfect choice for web development:
Fast
Go is a compiled language, which means that it is much faster than interpreted languages like JavaScript. This is important for web applications, as users expect fast loading times.
Efficient
Go is a very efficient language, which means that it uses less memory and CPU resources than many other languages. This is important for server-side applications, as it can help to reduce costs and reduce environment impact.
Secure
Go is a very secure language, which means that it is less vulnerable to security threats than interpreted languages. This is important for web applications, as users expect their data to be safe.
Powerful
Go is a very powerful language, which means that it can be used to build complex web applications.
Easy to use
Go is a rather easy language to learn and use, even for beginners.
Simple to deploy
Deploying an web application is about first compile Go into "machine code". Then transfer the compiled Go files together with other files (HTML, CSS, JavaScript etc) to the web server. Then start the Go built in web server. No app engines. Only Nginx (which is my prefered "proxy web server").
The function that creates and populate the form
Creates and add data in one step. Writing to innerHTML means less flickering.
// write form to buffer an send to html body func get_card(w http.ResponseWriter, module string, mode string, val string) { page := module + "_" + mode data := json2map4id(module, val) var buf bytes.Buffer tpl.ExecuteTemplate(&buf, page, data) // write to buffer fmt.Fprint(w, buf.String()) // send to body }
The form function in the context
Here is the entire main.go that manages forms and translations.
package main import ( "bytes" "encoding/json" "fmt" "html/template" "net/http" "strings" "github.com/leonelquinteros/gotext" ) var tpl *template.Template var mainmenu string var submenu string var translations map[string]*gotext.Po var usr_lang string //one time init func init() { translations = make(map[string]*gotext.Po) languages := []string{"en", "es", "de", "sv"} for _, lang := range languages { path := "./public/locale/" + lang + ".po" langPo := gotext.NewPo() langPo.ParseFile(path) translations[lang] = langPo } tpl = template.Must(template.New("").Funcs(template.FuncMap{ "trans": trans, }).ParseGlob("./public/tmpl/*/*.html")) load_main() load_sub() http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("./public/img")))) http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./public/css")))) http.Handle("/icn/", http.StripPrefix("/icn/", http.FileServer(http.Dir("./public/icn")))) http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./public/js")))) http.Handle("/misc/", http.StripPrefix("/misc/", http.FileServer(http.Dir("./public/misc")))) } // start webserver and mux func main() { http.HandleFunc("/", endpoint) http.ListenAndServe(":9098", nil) } //function that is called from the templates func trans(key string) string { path := "./public/locale/" + usr_lang + ".po" // translationsMux.Lock() po, ok := translations[usr_lang] if !ok { po = gotext.NewPo() po.ParseFile(path) translations[usr_lang] = po } // translationsMux.Unlock() return po.Get(key) } // fetch language setting from cookie func usr_getlang(r *http.Request) string { lang, _ := r.Cookie("lang") if lang != nil { usr_lang = lang.Value } else { usr_lang = "en" } return usr_lang } // dynamic endpoints func endpoint(w http.ResponseWriter, r *http.Request) { module, mode, val := getpath(r.URL.Path) usr_getlang(r) fmt.Println(module + mode + val) var page string switch module { case "robots.txt": http.ServeFile(w, r, "public/misc/robots.txt") case "sitemap.xml": http.ServeFile(w, r, "public/misc/sitemap.xml") case "favicon.ico", "favicon-32x32.png", "favicon-16x16.png": return case "main": get_main(w) return case "sub": get_sub(w, val) return case "": module = "home" } switch mode { case "edit", "new", "view", "find", "goto", "status", "timer": get_card(w, module, mode, val) default: page = module + ".html" set_header(w) data := json2map(module, mode, val) tpl.ExecuteTemplate(w, page, data) } } func set_header(w http.ResponseWriter) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "*") } // write form to buffer an send to html body func get_card(w http.ResponseWriter, module string, mode string, val string) { page := module + "_" + mode fmt.Println(page) data := json2map4id(module, val) var buf bytes.Buffer tpl.ExecuteTemplate(&buf, page, data) fmt.Fprint(w, buf.String()) } // navigation from cache func get_main(w http.ResponseWriter) { var menu []map[string]interface{} if err := json.Unmarshal([]byte(mainmenu), &menu); err != nil { fmt.Println(err.Error()) } var buf bytes.Buffer tpl.ExecuteTemplate(&buf, "main.html", menu) fmt.Fprint(w, buf.String()) } // navigation from cache func get_sub(w http.ResponseWriter, submenu string) { submenu = filter_sub(submenu) var menu []map[string]interface{} if err := json.Unmarshal([]byte(submenu), &menu); err != nil { fmt.Println(err.Error()) } var buf bytes.Buffer tpl.ExecuteTemplate(&buf, "sub.html", menu) fmt.Fprint(w, buf.String()) } // split url func getpath(path string) (module, mode, val string) { parts := strings.Split(path, "/") switch len(parts) { case 4: val = parts[3] fallthrough case 3: mode = parts[2] fallthrough case 2: module = parts[1] } return // Named return values are used, so just return here } // API call for all records func json2map(module string, mode string, val string) interface{} { // call the API and get body url := "https://api3.go4webdev.org/" + module + "/all" resp, err := http.Get(url) if err != nil { fmt.Println(err.Error()) } defer resp.Body.Close() // json to map var result interface{} err = json.NewDecoder(resp.Body).Decode(&result) if err != nil { fmt.Println(err.Error()) } return (result) } //API call for one id func json2map4id(module string, val string) interface{} { // call the API and get body url := "https://api3.go4webdev.org/" + module + "/id/" + val resp, err := http.Get(url) if err != nil { fmt.Println(err.Error()) } defer resp.Body.Close() // json to map var result interface{} err = json.NewDecoder(resp.Body).Decode(&result) if err != nil { fmt.Println(err.Error()) } return (result) }