A short walk on how to setup a go server using HTTP package provided by itself. Before jumping to framework I recommend you to explore and understand the packages provided by the particular programming language.
Before jumping directly to the code we need to know how go
structure the HTTP package so we need to jump to another code
i.e server.go
[](https://cs.opensource.google/go/go/+/refs/tags/go1.21.0:src/net/http/server.go)
I extract the code from the above link in case if you are too lazy to have another tab
- serveMux which type is struct
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return new(ServeMux) }
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
-
Handler
type Handler interface { ServeHTTP(http.ResponseWriter, *http.Request) signature }
3.Handle i.e func (mux *ServeMux) Handle(path string, handler Handler)
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
}
4.HandleFunc
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
lets write the code to set up the server
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"time"
)
type foo struct {
l *log.Logger
}
// we can create a constructor function
func newFoo(l *log.Logger) *foo{
return &(l)
}
/* we need to implement a ServeHTTP function in order to use http.Handle because it takes handler as argument.Handler is an interface which has ServeHTTP signature ref 2*/
func (f *foo) ServeHTTP(rw http.ResponseWriter, r*http.Request){
// handle all sort of things
rw.Write([]byte("Hello"))
return
}
func main() {
l := log.New(os.Stdout, "go", log.LstdFlags)
nf := newFoo(l)
/* we can create a new serveMux if not in listenAndServe,
default sever is use */
sm := http.NewServeMux()
// routing using Handle
sm.Handle("/",nf)
//routing using HandleFunc
sm.HandleFunc("/hf",func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("handle by Handle Func"))
return
})
// this server configuartion
s := &http.Server{
Addr: ":3000",
Handler: sm,
IdleTimeout : 120*time.Second,
ReadTimeout: 1 * time.Second,
WriteTimeout: 1*time.Second,
}
// we use go routine in order to independently execute
// and separate from main go routine
go func() {
err := s.ListenAndServe()
if err != nil {
l.Fatal(err)
}
}()
/* in order to shutdown the server properly means if we want to shutdown the server it make the existing request respond properly*/
sigChan := make(chan os.Signal)
signal.Notify(sigChan, os.Interrupt)
signal.Notify(sigChan,os.Kill)
sig := <- sigChan //this line blocks the waits for signal
fmt.Println("gracefully shutting down server", sig)
tc, f :=context.WithTimeout(context.Background(), 30*time.Second)
f()
s.Shutdown(tc)
}
---
That's all :)
Top comments (0)