1 of 61

Developing Web Apps

in Go Language

Juan E. Vargas

https://bit.ly/4cUMA1n

2 of 61

Outline

  • GoLang
  • Web Apps
  • WebApp in GoLang
  • Examples

Covering in detail the content in these slides may take N lectures of a standard CS course about web development, because the topics that must be covered include:

3 of 61

Go Language

Go has become by far my favorite computer programming language.

See

https://goo.gl/osizt3

https://bit.ly/4fmuE1i

4 of 61

Web Apps, Microservices and Go

One of the main reasons for developing Web apps and microservices in Go is the growing number of libraries and tools available at the server and the client side.

Another reason is Go’s native concurrency features.

Some people consider that server-side HTML generation is not the best way to build web apps. The most current trend is to do as much of the rendering as possible on the client side using JavaScript.

Apps whose UI is fully JS-driven are sometimes called Single Page Applications (SPA), and in the opinion of some who know more that me, SPAs are a better architecture and the way to go (no pun intended) especially for microservices.

5 of 61

Web Apps, SPA and Go

Under the SPA model, the server only serves data, typically as JSON, eliminating the need for construction of HTML content there.

The complexities involved in using a scripting language on the server are, in the view of many, is not worth the trouble, especially when considering that Python or Ruby bring so little when all of the output is done via JSON.

Go native support of concurrency eliminates the need of using a global interpreter lock mechanism or GIL. That mechanism is used in Python, Ruby, etc to synchronize thread execution, which is how Apache server and other frameworks handle multiple concurrent requests.

6 of 61

Web Dev and Go

Using Go, there is no need to add language-specific libraries on the server to handle concurrency, because Go runs concurrency natively.

This significantly reduces the complexity of web development, because there is no need to constantly update runtime API versions and/or concurrency tools; Go already provides concurrency at a binary level.

Go can run concurrent tasks in the background, thus no need for tools like Resque.

Go can run web apps as a single process, making caching trivial. As a consequence, APIs like Memcached or Redis are not necessary either.

Go can handle an unlimited number of parallel connections, eliminating the need for a front-end guard like Nginx.

7 of 61

Web Dev and Go

With Go, the tall stack of Python, Ruby, Bundler, Virtualenv, Unicorn, WSGI, Resque, Memcached, Redis, etc is reduced to just one binary.

The only other component that might be needed is a decent database (PostgreSQL, MySQL,...).

It’s important to note that all of these tools could be used, but with Go, there is the option of working without them.

Additionally, a Go program will easily outperform any Python/Ruby app by at least one order of magnitude. Also, Go requires less memory and fewer lines of code.

8 of 61

Background

We need to explore/review/understand a few key ideas such as

  1. Go objects and interfaces

  • Understand how the Go HTTP package uses interfaces and objects.

  • Decide what are the elements making up the data that will be exchanged between the client and the server.

  • Decide how to store that data. For now we will use gob, the go binary format.

  • Go Forms

  • Use templates to render pages

9 of 61

Objects in Go

An object in Go is a value or a variable that has methods; a method is a function associated to a type.

type Circle struct {

x, y, r float64

}

func (o *Circle) area() float64 {

return math.Pi * o.r*o.r

}

func main () {

c := Circle{0,0,5}

ac := c.area()

}

Note the different signatures in main and in area

// area is a method associated to objects of type Circle

func (o type) area ( args ) { body }

//main is a standard func

func main ( args ) { body }

10 of 61

An interface is a named collection of method signatures.

type Circle struct {� x, y, r float64�}

func (c *Circle) area() float64 {� return math.Pi * c.r*c.r�}

Suppose we have the structs Circle and a Rectangle as defined below.

We could write methods called area() for both types that return a float64 value:

type Rectangle struct {� x1, y1, x2, y2 float64�}

func (r *Rectangle) area() float64 {� l := distance(r.x1, r.y1, r.x1, r.y2)� w := distance(r.x1, r.y1, r.x2, r.y1)� return l * w�}

c := Circle{0,0,5}

ac := c.area()

r := Rectangle{0,0,5,5}

ar := r.area()

in o.method()

o is called receiver

11 of 61

type Shape interface {� area() float64�}

Suppose we add an interface called Shape as

func totalArea (shapes Shape) float64 {� var area float64� for _, s := range shapes {� area += s.area()� }� return area�}

c := Circle{0,0,5}

r := Rectangle{0,0,5,5}

fmt.Println( totalArea(&c, &r) )

totalArea accepts as arguments an arbitrary number of Shape objects and returns the sum of their areas, as calculated by the corresponding area() methods defined for circle and rectangle.

totalArea is a variadic function

12 of 61

13 of 61

The entire app is just 69 lines of code !

14 of 61

Challenge: Write and run in ~15 minutes an app that contains the code from slides 12, 13.

15 of 61

Using Go Objects and Interfaces for HTTP Development

In essence, HTTP development consists of

  1. A Browser making an HTTP request with some information.
  2. A Server processing the request and returning a response.

Browser

Server

HTTP REQUEST

HTTP RESPONSE

16 of 61

Using Go Objects and Interfaces for HTTP Dev

HTTP REQUEST

HTTP RESPONSE

Request Line

HTTP Headers

Status Line

HTTP Headers

content

The building block that defines http package operations in GoLang is the Http.Handler interface

type Handler interface {� ServeHTTP(ResponseWriter, *Request)�}

17 of 61

The Http.Handler interface defines the operations of the Http Package

Recall that an interface is a typed collection of method signatures.

type Handler interface {� ServeHTTP(ResponseWriter, *Request)�}

HTTP REQUEST

HTTP RESPONSE

  1. The Handler calls the ServeHTTP interface on every incoming request.
  2. The http.Request obj contains all the information related to the request.
  3. The ResponseWriter interface can be used to provide a response to the obj request.
  4. Using the io.Writer interface, we can produce nicely formatted responses or write into a file or render into a page.

18 of 61

package main�import (� "fmt"� "log"� "net/http"�)��type helloHandler struct{}��func (h helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {� fmt.Fprintf(w, "hello, you are in %s\n", r.URL.Path)�}�

func main() {� err := http.ListenAndServe(":1234", helloHandler{})� log.Fatal(err)�}

ServeHTTP is a method associated to the helloHandler interface

curl localhost:1234/foo/bar

func main() { } is a standard func

19 of 61

The simplest e-Commerce site

The code below is from the book “The Go Programming Language” by Donovan and Kernighan. It prints the name and price of items in a “db” store, created as a map

type dollars float32

type database map[string]dollars

func (d dollars) String() string {

return fmt.Sprintf("$%.2f", d)

}

func (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {

for item, price := range db { fmt.Fprintf(w, "%s: %s\n", item, price) }

}

func main() {

db := database{"shoes": 50, "socks": 5}

log.Fatal(http.ListenAndServe("localhost:8000", db))

}

20 of 61

The simplest e-Commerce site

Adding a “/list” and “/price” url

func (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {

switch req.URL.Path {

case "/list":

for item, price := range db {

fmt.Fprintf(w, "%s: %s\n", item, price)

}

case "/price":

item := req.URL.Query().Get("item")

price, ok := db[item]

if !ok {

w.WriteHeader(http.StatusNotFound) // 404

fmt.Fprintf(w, "no such item: w.WriteHeader(http.StatusNotFound) // 404

fmt.Fprintf(w, "no such page: %s\n", req.URL)

}

}

}

We could keep on adding cases within ServeHTTP, or, we could use a method dispatching mechanism to serve each request

21 of 61

package main

import (

"fmt"

"log"

"net/http"

)

func main() {

h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

fmt.Fprintf(w, "hello, you are in %s\n", r.URL.Path)

})

err := http.ListenAndServe(":1234", h)

log.Fatal(err)

}

A HandlerFunc type is an adapter that allows calling ordinary functions as HTTP handlers.

If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.

curl localhost:1234/foo/bar

22 of 61

func main() {

h := http.NewServeMux()

h.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {

fmt.Fprintln(w, "Hello, you are in foo!")

})

h.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {

fmt.Fprintln(w, "Hello, you are in bar!")

})

h.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

w.WriteHeader(404)

fmt.Fprintln(w, "You are done. Go home")

})

err := http.ListenAndServe(":1234", h)

log.Fatal(err)

}

Using HandlerFunc and ServeMux we can have different methods serving different behaviors for different entry points.

This is much better than having to code behavior as if or switch statements

curl localhost:1234/foo

curl localhost:1234/bar

curl localhost:1234

23 of 61

The Power of method Dispatching

Note the signature of h.Handle:

( “/” , pageNumber( i ) )

each call to h.Handle finds ServeHTTP and passes

the value in i to the responseWriter w

24 of 61

ServeHTTP is a method which in this case dispatches http requests from objects of type pageNumber to the http server

25 of 61

1

2

3

We can even trace the execution with VSC debugger

26 of 61

Web Dev and Go

The writing of this part of the doc is a summary from the materials available at the URL below, that contains an article about using Go APIs to develop the server side and the client side of a simple yet fully functional wiki as a SPA:

https://golang.org/doc/articles/wiki/

The code in that article shines simplicity and elegance. It presents the Go APIs by following a stepwise evolution from the simplest possible wiki to a fully functional wiki (including the client and the server side), which is quite remarkable.

27 of 61

wiki.go

func main() {

http.HandleFunc("/view/", makeHandler(viewHandler))

http.HandleFunc("/edit/", makeHandler(editHandler))

http.HandleFunc("/save/", makeHandler(saveHandler))

http.ListenAndServe(":1234", nil)

}

A typical wiki provides three operations:

edit an existing page or a new page,

display (view) a page,

save a page.

In Golang, execution starts at main. The main function below launches these operations:

28 of 61

http://localhost:1234/view/new

If the page been requested does not exist for view, the app redirects the request to the edit handler to create one.

How does that happen?

The magic is part of the routing provided by the interfaces and objects in GoLang http package

29 of 61

wiki.go

The magic is in the writing of the function handlers.

Before going there we need to cover a few preliminaries.

First we need to import the APIs that we will use.

Then we need to define the structure of a wiki page, and with that, how to save a page into a file and how to read (load) a page from a file.

30 of 61

wiki.go

package main

import (

"html/template"

"io/ioutil"

"net/http"

"regexp"

)

type Page struct {

Title string

Body []byte

}

func (p *Page) save() error {

filename := p.Title + ".txt"

return ioutil.WriteFile(filename, p.Body, 0600)

}

func readPage(title string) (*Page, error) {

filename := title + ".txt"

body, err := ioutil.ReadFile(filename)

if err != nil {

return nil, err

}

return &Page{Title: title, Body: body}, nil

}

31 of 61

wiki.go

A Page is just a struct with two items, a Title and a Body.

The method save gets a pointer to a Page as a parameter. The contents of the page are written into a file whose name is title.txt. The method returns an empty error (nil) if successful. If the operation fails, save returns a non-nil error object.

The function readPage gets a string parameter (title) which is expected to be the name of the file. If the file read is successful the function returns a pointer to a page and a nil error. If the read operation fails, the function returns a page pointer object with no content and a non-nil error.

32 of 61

wiki.go

func editHandler(w http.ResponseWriter, r *http.Request, title string) {

p, err := readPage(title)

if err != nil {

p = &Page{Title: title}

}

renderTemplate(w, "edit", p)

}

editHandler is the simplest of the three. The parameters are (w,r,title). The first two are objs from the http package. Note that r is really not used. It is there only for consistency with the other two handlers, which are created via a “make handler” function.

The code gets a page from a file. If the page is there, error is nil and edit template is rendered with the page content. If page is not there then error is non-nil and an empty page is rendered

33 of 61

Templates

Good news: Go has a template package !

Go Templates are similar to jinja2 templates from Python. There are a few sites where the two are compared.

The Go template package (html/template) implements data-driven templates for generating HTML output safe against code injection. It provides the same interface as package text/template and should be used instead of text/template whenever the output is HTML.

The package is mostly used in web applications to display data in a structured way at the client’s browser.

A benefit not found in other implementations (Python, Java, etc) is that Go templates provide automatic escaping of data. What does this mean? There is no need to worry about XSS attacks because Go parses the HTML template and escapes all inputs before displaying it to the browser.

Templates are HTML “macro expansions” that use the notation {{ action item … }}

The template engine reads .html files and expands sections denoted by {{ action }} from Go data structures.

The “macro expansions” produce text.

34 of 61

Below is a list of some of the actions (from the Go Documentation)

{{/* a comment */}}

{{pipeline}}

The default textual representation (the same as would be printed by fmt.Print)

of the value of the pipeline is copied to the output.

{{if pipeline}} T1 {{end}}

If the value of the pipeline is empty, no output is generated; otherwise, T1

is executed. The empty values are false, 0, any nil pointer or interface value,

and any array, slice, map, or string of length zero. Dot is unaffected.

{{if pipeline}} T1 {{else}} T0 {{end}}

If the value of the pipeline is empty, T0 is executed; otherwise, T1 is executed.

Dot is unaffected.

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}

To simplify the appearance of if-else chains, the else action

of an if may include another if directly; the effect is exactly

the same as writing {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}

Actions, Part 1

35 of 61

{{range pipeline}} T1 {{end}}

The value of the pipeline must be an array, slice, map, or channel.

If the value of the pipeline has length zero, no output is rendered; otherwise,

dot is set to the successive elements of the items in T1. If the value is a map

and the keys are of a type with a defined order ("comparable"), the elements will

be visited in sorted key order.

{{range pipeline}} T1 {{else}} T0 {{end}}

The value of the pipeline must be an array, slice, map, or channel.

If the value of the pipeline has length zero, dot is unaffected and

T0 is executed; otherwise, dot is set to the successive elements

of the array, slice, or map and T1 is executed.

{{template "name"}}

Actions, Part 2

36 of 61

Templates

<h1>{{.PageTitle}}</h1>

<ul>

{{range .Todos}}

{{if .Done}}

<li class="done">{{.Title}}</li>

{{else}}

<li>{{.Title}}</li>

{{end}}

{{end}}

</ul>

Using templates in Go is simple.

The code shows a ToDo list, written as a HTML

unordered list <ul> tag </ul>.

The code in blue is HTML. The code in white is processed by the template library.

The data passed from/to go/html can be any kind of Go’s data structures, including simple strings or numbers, or even nested data structures as shown the code will show.

To access the data in a template, the top most variable is access by {{.}}. The dot inside the curly braces is the root element of the data (typically a list) and is called the pipeline.

37 of 61

Templates Control Structures

To get a detailed list of all possible structures visit: https://pkg.go.dev/text/template#hdr-Actions

Define a comment

{{/* a comment */}}

Render the root element

{{.}}

Example: render the “Title”-field in a nested element

{{.Title}}

If Statement

{{if .Done}}<blabla>{{else}}<blabla>{{end}}

Loops over the elements of a list and renders each using {{.}}

{{range .Todos}} {{.}} {{end}}

Defines a block named “content”

{{block "content" .}} {{end}}

Go’s template language contains a rich set of control structures to render HTML. The list below summarizes the most commonly used.

38 of 61

Templates Sample1

func sample01() {

// Define a template.

const letter = `

Dear {{.Name}},

{{if .Attended}}

It was a pleasure to see you at the wedding.

{{- else}}

It is a shame you couldn't make it to the wedding.

{{- end}}

{{with .Gift -}}

Thank you for the lovely {{.}}.

{{end}}

Best wishes,

Josie

`

// Prepare some data to insert into the template.

type Recipient struct {

Name, Gift string

Attended bool

}

var recipients = []Recipient{

{"Aunt Mildred", "bone china tea set", true},

{"Uncle John", "moleskin pants", false},

{"Cousin Rodney", "", false},

}

// Create a new template and parse the letter into it.

t := template.Must(template.New("letter").Parse(letter))

// Execute the template for each recipient.

for _, r := range recipients {

err := t.Execute(os.Stdout, r)

if err != nil {

log.Println("executing template:", err)

}

}

}

39 of 61

Templates Sample2

func sample02() {

// print one name on each line

const (

master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`

overlay = `{{define "list"}} {{join . ", "}}{{end}} `

)

var (

funcs = template.FuncMap{"join": strings.Join}

guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"}

)

masterTmpl, err := template.New("master").Funcs(funcs).Parse(master)

if err != nil {

log.Fatal(err)

}

if err := masterTmpl.Execute(os.Stdout, guardians); err != nil {

log.Fatal(err)

}

// print all names in a single line

overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay)

if err != nil {

log.Fatal(err)

}

if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil {

log.Fatal(err)

}

}

println "-" list[i]

println "-" list[i]

alias for fmt.Println(args) https://pkg.go.dev/text/template#hdr-Examples

40 of 61

Templates Sample3

func sample03() {

tmpl := template.Must(template.ParseFiles("layout.html"))

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

data := TodoPageData{

PageTitle: "My TODO list",

Todos: []Todo{

{Title: "Task 1", Done: false},

{Title: "Task 2", Done: true},

{Title: "Task 3", Done: true},

},

}

tmpl.Execute(w, data)

})

http.ListenAndServe(":1234", nil)

}

<h1>{{.PageTitle}}</h1>

<ul>

{{range .Todos}}

{{if .Done}}

<li class="done">{{.Title}}</li>

{{else}}

<li>{{.Title}}</li>

{{end}}

{{end}}

</ul>

type Todo struct {

Title string

Done bool

}

type TodoPageData struct {

PageTitle string

Todos []Todo

}

4

1

2

3

5

41 of 61

Templates

func sample03() {

tmpl := template.Must(template.ParseFiles("layout.html"))

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

data := TodoPageData{

PageTitle: "My TODO list",

Todos: []Todo{

{Title: "Task 1", Done: false},

{Title: "Task 2", Done: true},

{Title: "Task 3", Done: true},

},

}

tmpl.Execute(w, data)

})

http.ListenAndServe(":1234", nil)

}

html file

HandleFunc

Learn Templates Demo

42 of 61

render header

scope of range

render from fields

render from fields

render from fields

render from fields

reference by field

reference by field

when btn clicked go to

q/vote_nvc/XVC

43 of 61

render header

scope of range

scope of range

title field

content field

PVC

NVC

btn

btn

44 of 61

Edit Template

View Template

<h1>Editing {{.Title}}</h1>

<form action="/save/{{.Title}}" method="POST">

<div><textarea name="body" rows="20" cols="80">

{{printf "%s" .Body}}</textarea>

</div>

<div>

<input type="submit" value="Save">

</div>

</form>

<h1>{{.Title}}</h1>

<p>[<a href="/edit/{{.Title}}">edit</a>]</p>

<div>{{printf "%s" .Body}}</div>

Code injection occurs when the compiler sees the pattern

{{ goCode }}

within an html file

45 of 61

wiki.go

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {

p, err := loadPage(title)

if err != nil {

http.Redirect(w, r, "/edit/"+title, http.StatusFound)

return

}

renderTemplate(w, "view", p)

}

The viewHandler gets params (w, r, title) to load a page or to start the editing of a new one.

If page is not there, p is empty and error is non-nil. This causes the handler to redirect request to editHandler.

Either way, the viewHandler uses the view template for rendering the page

46 of 61

wiki.go

func saveHandler(w http.ResponseWriter, r *http.Request, title string) {

body := r.FormValue("body")

p := &Page{Title: title, Body: []byte(body)}

err := p.save()

if err != nil {

http.Error(w, err.Error(), http.StatusInternalServerError)

return

}

http.Redirect(w, r, "/view/"+title, http.StatusFound)

}

The saveHandler gets params (w, r, title). The body is extracted from the response’s page and the title is used as file name. Note how the func save is called: save gets as argument a page pointer, which in fact is the “target” of the function when it is called as p.save().

47 of 61

wiki.go

var templates = template.Must(template.ParseFiles("edit.html", "view.html"))

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {

err := templates.ExecuteTemplate(w, tmpl+".html", p)

if err != nil {

http.Error(w, err.Error(), http.StatusInternalServerError)

}

}

templates is a global variable used to save the output of parsing the view and edit templates. In this way the parsing is done once and keeping the parsed output improves efficiency.

renderTemplate gets params (w, tmpl, p). This function is used to render into the view or the edit template.

48 of 61

wiki.go

var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {

return func(w http.ResponseWriter, r *http.Request) {

m := validPath.FindStringSubmatch(r.URL.Path)

if m == nil {

http.NotFound(w, r)

return

}

fn(w, r, m[2])

}

}

makeHandler is a very interesting function. It gets param (fn) to return an obj of type http.HandlerFunc. Yes, that is correct, the return is a function!

49 of 61

wiki.go

func main() {

http.HandleFunc("/view/", makeHandler(viewHandler))

http.HandleFunc("/edit/", makeHandler(editHandler))

http.HandleFunc("/save/", makeHandler(saveHandler))

http.ListenAndServe(":1234", nil)

}

50 of 61

The entire app is just 130 lines of GoLang code !

51 of 61

52 of 61

The entire app is just 130 lines of GoLang code !

53 of 61

Web Client

Web Server

mkcog

GoWa: MakinaCognika: ML in Pure Go

Go as a System Platform

54 of 61

GoWaMain

GoWa Main is the "V2" of a lib I wrote to demo writing web apps in entirely Go.

The version is Go 1.22.4, which must be declared in go.mod

## UPDATE June 19, 2024

The code in

The go.mod file was created as follows:

cd /drv3/hm3/code/go/src/gowamain

go mod init

go mod tidy

55 of 61

GoWaMain

/*

GoWa is a WebApp written n Go. The purpose is to create a fully functional Web App that includes a web server,

a client, and simple code for data science, with access/interface to a fully functional DB, most likely under MySql.

*/

package main

import (

"fmt"

gowa "gowa/gowa/lib"

"log"

"net/http"

"os"

"os/exec"

"runtime"

)

func openBrowser(url string) bool {

var args []string

switch runtime.GOOS {

case "darwin":

args = []string{"open"}

case "windows":

args = []string{"cmd", "/c", "start"}

default:

args = []string{"xdg-open"}

}

cmd := exec.Command(args[0], append(args[1:], url)...)

return cmd.Start() == nil

}

func main() {

var url = "http://localhost:1233"

openBrowser(url)

fmt.Printf("Process ID %d ", os.Getpid())

// code below is needed to add .css styles into the html files

http.Handle(gowa.GoWaDirCss, http.StripPrefix(gowa.GoWaDirCss,

http.FileServer(http.Dir(gowa.GoWaDirCss))))

http.HandleFunc("/", gowa.Gowa) // set router

http.HandleFunc("/pgPython", gowa.PgPython) // set router

http.HandleFunc("/hello", gowa.HelloName) // set router

http.HandleFunc("/login", gowa.Login) // set router

http.HandleFunc("/sqlquery", gowa.SqlQuery) // set router

http.HandleFunc("/server2", gowa.Server2) // set router

http.HandleFunc("/server3", gowa.Server3) // set router

http.HandleFunc("/server4", gowa.Server4) // set router

http.HandleFunc("/server5", gowa.Server5) // set router

http.HandleFunc("/XssLogin", gowa.XssLogin) // set router

http.HandleFunc("/vrb", gowa.Vrb) // set router

http.HandleFunc("/vdd", gowa.Vdd) // set router

http.HandleFunc("/vcb", gowa.Vcb) // set router

// use these two once mkcog is added to this app

http.HandleFunc("/slrp", gowa.SLRP) // SLRP = Simple LR Page

http.HandleFunc("/mlrp", gowa.MLRP) // MLRP = Multi-variable LR Page

http.HandleFunc("/upload", gowa.UploadFile) // set router

err := http.ListenAndServe(":1233", nil) // listen at port 1233

if err != nil {

log.Fatal("ListenAndServe: ", err)

}

fmt.Println("DONE")

}

ref to gowa

56 of 61

GoWa

57 of 61

GoWa

The ../lib subdirectory contains the files.go where the handlers and functions are defined

The ../lib subdirectory contains the files.go where the handlers and functions are defined

58 of 61

DEMOS

WebAppCSS_2024_0708

GoWa

Moderator

59 of 61

Mod App in Go Language

Juan E. Vargas

https://bit.ly/4cUMQNT

60 of 61

what’s next?

We only scratched the surface. The http package contains tons of constants, types and methods that deserve attention

61 of 61

Computing is about insights, not just numbers

  • Computing methods use numbers to simulate real-world processes and/or estimate parameters about those processes.

  • This implies that there is a purpose behind computing.

  • If the purpose is to gain insights about the processes around us, then rather than studying isolated formulations, we must also connect the dots to understand the implications from different perspective and diverse fields of study.