Avatar A personal blog about technical things I find useful. Also, random ramblings and rants...

Webserver part-1

Working with golang webserver.

image

Basic Webservice in Golang.

http.ListenAndServe function takes two parameters, addr string and handler.

package main

import "net/http"

func main(){
    http.ListenAndServe(":8080", nil)
    //addr string can be ip address followed by port. 
    //Just port signifies that every ip address on the server.  
}

Running the above code restirns the following:

curl -v http://localhost:8080
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Mon, 12 Aug 2024 15:42:04 GMT
< Content-Length: 19
< 
404 page not found
* Connection #0 to host localhost left intact

Since no request is sent, the server returns a 404. The requests are handled by http.HandleFunc() handler in Golang. We can refer the documentation how http.HandleFunc is used. https://pkg.go.dev/net/http#HandleFunc The implementation of DefaultServeMux can be seen at https://go.dev/src/net/http/server.go The updated code is:

package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(http.ResponseWriter, *http.Request) {
		log.Println("hello world")
    //This HandleFunc is a convinience method, it takes the function 
    //and creates a http handler from it  and adds it to DefaultServeMux    

	})
	http.ListenAndServe(":8080", nil)
	//addr string can be ip address followed by port.
	//Just port signifies that every ip address on the server.
    //HandleFunc is a convinience method which registers a function to a path on the DefaultServeMux. 
    //DefaultServeMux is http handler, everything related to server in go is http handler. 
    //Since the second parameter on ListenAndServe handler is nil, it uses DefaultServeMux.

    //When we call ListenAndServe, it uses DefaultServeMux as its root handler and 
    //determines which code block needs to be executed on the type of request.


}

The above code prints hello world on the server terminal.

Adding a new handler goodbye

package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(http.ResponseWriter, *http.Request) {
		log.Println("hello world")

	})

	http.HandleFunc("/goodbye", func(http.ResponseWriter, *http.Request) {
		log.Println("goodbye")
	})


	http.ListenAndServe(":8080", nil)
}

When the above code is run, the respose goodbye is returned when url is hit with /goodbye. However, when anything else is passed onto the url, it return hello world.

Using ResponseWriter and Request interfacs to read and write to our functions. https://pkg.go.dev/net/http#ResponseWriter https://pkg.go.dev/net/http#Request

Making changes to the HandleFunc taking care of “/” url path. func(rw http.ResponseWriter, r *http.Request)

rw (short for ResponseWriter): Represents the http.ResponseWriter interface, which is used to write the HTTP response back to the client.

r (short for Request): Represents a pointer to an http.Request struct, which contains details about the HTTP request made by the client.

Next we use ioutil ro read the request body.

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
		log.Println("hello world")
		// Adding response writer and request variables to the http handler.
		d, err := ioutil.ReadAll(r.Body)
		if err != nil {
			rw.WriteHeader(http.StatusBadRequest)
			rw.Write([]byte("Bazinga!"))
			//same things can be written replacing the above two lines and using the
			//http error package.
			//http.Error(rw, "Bazinga!", http.StatusBadRequest)
			return
		}

		fmt.Fprintf(rw, "Hello %s", d)
	})

	http.HandleFunc("/goodbye", func(http.ResponseWriter, *http.Request) {
		log.Println("goodbye")
	})
	http.ListenAndServe(":8080", nil)
	//addr string can be ip address followed by port.
	//Just port signifies that every ip address on the server.
}

all tags