Un exemplu de server in golang apelat cu functii JavaScript descrise in JS Promises, Fetch and Arrow Functions.
package main
import (
"embed"
"encoding/json"
"fmt"
"html/template"
"net/http"
"time"
"github.com/braintree/manners"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
)
//go:embed static
var static_fs embed.FS
//go:embed templates
var tpl_fs embed.FS
var tpl, _ = template.ParseFS(tpl_fs, "templates/*.tmpl") // ignor eroarea
// key must be 16, 24 or 32 bytes long (AES-128, AES-192 or AES-256)
var key = make([]byte, 16)
var store *sessions.CookieStore
const session_cookie_name = "gowebsession"
type dict map[string]interface{}
func main() {
fmt.Println("Start app.")
r := mux.NewRouter()
store = sessions.NewCookieStore(key)
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
const time_format = "02/Jan/2006 15:04:05"
// now := time.Unix(time.Now().Unix(), 0).Format((time_format))
now := time.Now().Format((time_format))
// get session, update, then save
session, _ := store.Get(r, session_cookie_name)
if session.Values["cnt"] == nil {
session.Values["cnt"] = 0
}
session.Values["cnt"] = session.Values["cnt"].(int) + 1
session.Values["now"] = now
session.Save(r, w)
fmt.Printf("index session values = %v\n", session.Values)
title := "go App with Webserver"
data := dict{
"title": title,
}
tpl.ExecuteTemplate(w, "index", data)
})
r.HandleFunc("/x", func(w http.ResponseWriter, r *http.Request) {
// oprire server de web folosing modulul "manners"
fmt.Fprintf(w, "Server shutting down ...")
go func() {
time.Sleep(1 * time.Second)
fmt.Println("Server shutting down ...")
manners.Close()
}()
})
r.HandleFunc("/test/{oid}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
oid := vars["oid"]
fmt.Printf("/test m=%s oid=%s q=%v\n", r.Method, oid, r.URL.Query())
// post
decoder := json.NewDecoder(r.Body)
var args interface{} // generic - orice fel de obiect json
err := decoder.Decode(&args)
if err != nil {
fmt.Printf("\tError: %v\n", err)
} else {
fmt.Printf("\ttest POST args = %v\n", args)
prettyJSON, err := json.MarshalIndent(args, "", " ")
if err == nil {
fmt.Println(string(prettyJSON))
}
}
// time.Sleep(1 * time.Second) // for test timeout
var ret dict = dict{"ok": true, "method": r.Method, "da": false, "x": dict{"a": 1, "b": true, "c": dict{"ax": 33, "bx": 34}}}
w.Header().Set("Content-Type", "application/json")
jsonString, _ := json.Marshal(ret)
fmt.Fprint(w, string(jsonString))
})
r.PathPrefix("/static/").Handler(http.FileServer(http.FS(static_fs)))
addr := ":8080"
fmt.Printf("Start webserver on %s\n", addr)
err = manners.ListenAndServe(bindaddr, r)
if err != nil {
panic(err)
}
fmt.Println("End app.")
}
Exemplul de server de mai sus include, dupa compilare, continutul folderelor static si templates folosind modulul embed.
Pentru executia programului este nevoie numai de fisierul binar generat (aproximativ 9.6 mega), pentru ca in interiorul executabilului este inserat (embed) continutul folderelor static si templates.
Folderul templates contine cel putin 3 fisiere: index.tmpl, header.tmpl si footer.tmpl.
{{define "index"}}
{{template "header" .}}
<h3>{{.title}}</h3>
<script>
(async () => {
var ret = null
ret = await getFetch('/test/100?a=1&b=222')
if (typeof (ret) != 'object') console.log("Err", ret)
else console.log("call 1 =", ret)
ret = await postFetch('/test/200?a=333&b=444', { a: 1 })
if (typeof (ret) != 'object') console.log("Err", ret)
else console.log("call 2 =", ret)
})()
</script>
{{template "footer" .}}
{{end}}
{{define "header"}}
<html lang="en">
<head>
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/static/app.css">
<script src="/static/app.js"></script>
{{end}}
{{define "footer"}}
</body>
</html>
{{end}}
Folderul static contine fisiere .css si .js necesare aplicatiei livrate de serverul de web.