Creating http handler - go

I have main.go and I want changing to better structure(similarly main2.go ) due to if the proyect would grow up, would not be easy interpret for new developers the code.
My idea is create a folder called handle and put in it the file handle.go with all the handles methods, the trouble that I find is that I do not know how to set up http.HandleFunc("/R1", HandlerOne) and http.HandleFunc("/R2", HandlerTwo) in handler.go and call it from main2.go.
main.go
package main
import (
"fmt"
"net/http"
)
func HandlerOne(w http.ResponseWriter, req *http.Request) {
fmt.Println("message one")
}
func HandlerTwo(w http.ResponseWriter, req *http.Request) {
fmt.Println("message two")
}
func main() {
http.HandleFunc("/R1", HandlerOne)
http.HandleFunc("/R2", HandlerTwo)
err := http.ListenAndServe(":9998", nil)
if err != nil {
fmt.Printf("Server failed: ", err.Error())
}
}
main2.go
package main
import (
"fmt"
"net/http"
)
func main() {
// Call handle.go
err := http.ListenAndServe(":9998", nil)
if err != nil {
fmt.Printf("Server failed: ", err.Error())
}
}
handle.go
package handle
import (
"fmt"
"net/http"
)
func HandlerOne(w http.ResponseWriter, req *http.Request) {
fmt.Println("message one")
}
func HandlerTwo(w http.ResponseWriter, req *http.Request) {
fmt.Println("message two")
}
Note:
Thanks #kluyg for your answer. I going to add that i want that seems I do not explain very well:
That I want is create a function in
handle.go where can I can put all the mapping of the handles. i.e some like that
func SetUpMapping(...){
http.HandleFunc("/R1", HandlerOne)
http.HandleFunc("/R2", HandlerTwo)
..... //Others mapping
http.HandleFunc("/RN", HandlerN)
}
where ... should be one refence to http, but this is one package, and in the main something like code 3
code 3
main2.go
package main
import (
"fmt"
"net/http"
"handlers/handle"
)
func main() {
// Call handle.go
handle.SetUpMapping(...) // i dont know what parameter put here
err := http.ListenAndServe(":9998", nil)
if err != nil {
fmt.Printf("Server failed: ", err.Error())
}
}

I took your code and put main2.go into $GOPATH/handlers folder and handle.go in $GOPATH/handlers/handle folder. Then I changed main2.go to be
package main
import (
"fmt"
"net/http"
"handlers/handle"
)
func main() {
// Call handle.go
http.HandleFunc("/R1", handle.HandlerOne)
http.HandleFunc("/R2", handle.HandlerTwo)
err := http.ListenAndServe(":9998", nil)
if err != nil {
fmt.Printf("Server failed: ", err.Error())
}
}
It compiles and works fine. I believe this is what you asked for.
UPDATE
OK, you can add this to your handle.go
func SetUpMapping() {
http.HandleFunc("/R1", HandlerOne)
http.HandleFunc("/R2", HandlerTwo)
..... //Others mapping
http.HandleFunc("/RN", HandlerN)
}
then in main2.go
package main
import (
"fmt"
"net/http"
"handlers/handle"
)
func main() {
// Call handle.go
handle.SetUpMapping() // you don't need any parameters here
err := http.ListenAndServe(":9998", nil)
if err != nil {
fmt.Printf("Server failed: ", err.Error())
}
}

Related

how can i catch the error with errorgroup?

here I want the "run" function in the runner.go package to run continuously by using the "errorgroup". How can I catch this error later when it receives an error? Below is a sample code block that I want to do but fail.
Thank you.
main.go
package main
import (
"context"
"fmt"
"awesomeProject/runner"
"golang.org/x/sync/errgroup"
"time"
)
func main() {
ctx := context.Background()
g, ctx := errgroup.WithContext(ctx)
g.Go(func() (err error) {
return runner.Start(ctx, 1 * time.Second)
})
if err := g.Wait(); err != nil {
fmt.Println(err)
fmt.Println("app terminated")
}
}
runner.go
package runner
import (
"context"
"errors"
"fmt"
"time"
)
func Start(ctx context.Context, dur time.Duration) error {
ticker := time.NewTicker(dur)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return nil
case <-ticker.C:
run(ctx)
}
}
}
func run(ctx context.Context) error {
fmt.Println(time.Now().String())
return errors.New("run:error")
}

Understanding mux router in golang

here is my code trying to display a base64 image it worked before using mux.
I've used http handlefunc before using mux, here i want to use mux and get the value of key.
package main
import (
"fmt"
"net/http"
"strconv"
base64 "encoding/base64"
"log"
"io"
"io/ioutil"
"os"
"github.com/gorilla/mux"
)
var (
Trace *log.Logger
Info *log.Logger
Warning *log.Logger
Error *log.Logger
)
func Init(
traceHandle io.Writer,
infoHandle io.Writer,
warningHandle io.Writer,
errorHandle io.Writer) {
Trace = log.New(traceHandle,
"TRACE: ",
log.Ldate|log.Ltime|log.Lshortfile)
Info = log.New(infoHandle,
"INFO: ",
log.Ldate|log.Ltime|log.Lshortfile)
Warning = log.New(warningHandle,
"WARNING: ",
log.Ldate|log.Ltime|log.Lshortfile)
Error = log.New(errorHandle,
"ERROR: ",
log.Ldate|log.Ltime|log.Lshortfile)
}
func get_info(r *http.Request){
fmt.Println(r.RemoteAddr)
fmt.Println(r.Header.Get("x-forwarded-for"))
fmt.Println(r.UserAgent())
fmt.Println(r.Referer())
}
func pix(w http.ResponseWriter, r *http.Request) {
Info.Println("Hi there, I love %s!", r.URL.Path[1:])
vars := mux.Vars(r)
key := vars["key"]
Info.Println("key", key)
var cookie *http.Cookie
cookie , err := r.Cookie("csrftoken")
if (err != nil ){
fmt.Printf("error")
fmt.Println(err)
}
get_info(r)
fmt.Printf(cookie.Value)
w.Header().Set("Content-Type", "image/jpeg")
p, err := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAADMUlEQVRYw+2YTUgUYRjHZzOJIoNA+rrUyYNIRQgRHaLo4qFDBEGeunSxS9TFU0QEnhIh6IvokrUzO2uamRmbG6XmR/mVaKZpZVbYvvO143zszsxOz+yahNm+785sITEP72F3Z+adH8/zf5+PpagwtxKXj+Vj+Vg+lo/lY+W+WI4KpddKwWIQFUSF97nNLcLGZt75SiOHchEXfskDVmYjlowpiEoei3UT2ljcFJOpOd169C1Z2SuvgsdpB7cgzB16EV/byGM2xDIVPxQujKmBDF/2m2l0vFvmEin7N2v8kiiPiOeGlGHRvP1RdxA9eYtGR7pk2Pf6lI7RCoP2RaWkZWe3fsFc18hvesAHPGEFUc24ltnx3kyiCJwfRMs6dTXLdSIjO9Osal18qzKfE5V9coDxhlU7qS3uOyiaB55JDtkS2TKoLCLaOLPS4b02pQdCHiUfRKf653/d2kjZN6f10jYxI2EnrGk5H+2WsVi6ZZ8fVSmGQKaYyyFuR6ugmUtVrJo2C7HokeGq8447sYpOPBbo3XFzKC95626sZlz905sUM9XLGbXvtKtTOhZrQDApkhNNkiAOPo/viojh2YSZsj1aF2eQ5n2stuomNQjiiGQanrFufdCXP8gu8tbhjridJ6saVPKExXJrwlwfb3pnAg2Ut0tEBZFI8gza81Tik15DCDIoINQ7aQdBo90RMfrdwNaWLFY9opJGkBQrhCA/HXspQ8W1XHkN6vfWFiGH9ouwhdpJUFuy2JX3eg6uyqENpNHZYcUd02jcLMI2WO67UwZVv1G1HLMq3L83KuEbLPdY7IL2L42p0MMQiuzkq/ncwucOi6qPbWkWoPfCUsENpweUnP1EmE4XGhgagT72RyXolkSCHBbTU3By3fgJj8VyJW3CmSHl8oTWMJuYUUizVvtcsuyJ6J4J663CMLevXar/lJgnKNSgbphzKjriTn5i0F8eX9ODXnEzf6JHvjGtv+aNGdWCOEKnJRmpr5oFVQV8WTWglIKHMlPhv5uqQ1xGYfB5fRMPo+n2VmFbi7ChiS9oWBhZvXrI01TNLg7yPxt51v9rxMfysXwsH8vH+g+wfgDUr+5LcyNV4AAAAABJRU5ErkJggg==")
if err != nil {
http.Error(w, "internal error", 500)
return
}
w.Header().Set("Content-Length", strconv.Itoa(len(p))) //len(dec)
w.Write(p)
}
func main() {
Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
Info.Println("1")
r := mux.NewRouter()
Info.Println("2")
r.HandleFunc("/pix/{key}/pixel.gif", pix)
err := http.ListenAndServe(":9080", nil)
Info.Println("3")
if err != nil {
fmt.Println(err)
}
}
It seems that when i call http://localhost:9080/pix/2/pixel.gif
it doesn't call pix.
the url for calling it seems correct
any idea why ?
regards and thanks
It appears that you are not assigning r to anything, you should add the following at the end of your main:
http.Handle("/", r)

global recover handler for golang http panic

I want to create global err handler to send it by email.
package main
import (
"github.com/gorilla/mux"
"log"
"net/http"
)
func main() {
rtr := mux.NewRouter()
rtr.HandleFunc("/", withPanic).Methods("GET")
http.Handle("/", rtr)
log.Println("Listening...")
http.ListenAndServe(":3001", http.DefaultServeMux)
}
func withPanic(w http.ResponseWriter, r *http.Request) {
panic("somewhere here will be panic, but I don't know where exactly")
}
How to make it global. It would be easy if I know where error will occur
if err != nil {
sendMeMail(err)
}
But what to do in cases when I don't know exactly where an error will occur? So I should add a global recoverish handler. But how to do it exactly I don't know.
Update
I added defer recover to beginning of main but it never executes on requesting http://localhost:3001. So panic is not emailed.
package main
import (
"errors"
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
)
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
// find out exactly what the error was and set err
var err error
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = errors.New("Unknown panic")
}
if err != nil {
// sendMeMail(err)
fmt.Println("sendMeMail")
}
}
}()
rtr := mux.NewRouter()
rtr.HandleFunc("/", withPanic).Methods("GET")
http.Handle("/", rtr)
log.Println("Listening...")
http.ListenAndServe(":3001", http.DefaultServeMux)
}
func withPanic(w http.ResponseWriter, r *http.Request) {
panic("somewhere here will be panic, but I don't know where exactly")
}
You can wrap your handlers in a recovery middleware
package main
import (
"errors"
"github.com/gorilla/mux"
"log"
"net/http"
)
func main() {
m := mux.NewRouter()
m.Handle("/", RecoverWrap(http.HandlerFunc(handler))).Methods("GET")
http.Handle("/", m)
log.Println("Listening...")
http.ListenAndServe(":3001", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
panic(errors.New("panicing from error"))
}
func RecoverWrap(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
r := recover()
if r != nil {
var err error
switch t := r.(type) {
case string:
err = errors.New(t)
case error:
err = t
default:
err = errors.New("Unknown error")
}
sendMeMail(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}()
h.ServeHTTP(w, r)
})
}
func sendMeMail(err error) {
// send mail
}
You can take a a look at codahale recovery handler or negroni middleware for more details.
I believe that is what the gorilla recovery handler is for

Goroutines with http.HandleFunc

I want to know if code 1 manage internal goutines and can use all the cores of one CPU when the requets will increase(dozens) or if per each handler I have to put the key word go that indicate that the funcion handler will be manage by one gorotine like is show it in code 2, and so can use all the cores of the server.
code 1
package main
import (
"fmt"
"net/http"
)
func HandlerOne(w http.ResponseWriter, req *http.Request) {
fmt.Println("message one")
}
func HandlerTwo(w http.ResponseWriter, req *http.Request) {
fmt.Println("message two")
}
func main() {
http.HandleFunc("/R1", HandlerOne)
http.HandleFunc("/R2", HandlerTwo)
err := http.ListenAndServe(":9998", nil)
if err != nil {
fmt.Printf("Server failed: ", err.Error())
}
}
code 2
package main
import (
"fmt"
"net/http"
)
func HandlerOne(w http.ResponseWriter, req *http.Request) {
fmt.Println("message one")
}
func HandlerTwo(w http.ResponseWriter, req *http.Request) {
fmt.Println("message two")
}
func main() {
go http.HandleFunc("/R1", HandlerOne)
go http.HandleFunc("/R2", HandlerTwo)
err := http.ListenAndServe(":9998", nil)
if err != nil {
fmt.Printf("Server failed: ", err.Error())
}
}
Note: Both run without problems and you be able to test it with
curl -l http://localhost:9998/R1
or
curl -l http://localhost:9998/R2
Version 2 is wrong. Package http handles all this stuff for you.
Just make sure you invoke your program with an appropriate GOMAXPROCS, e.g. like GOMAXPROCS=4 ./main

Print to Log using Go Language Simple HTTP Server

I am trying to log the IP address of the requestor, what METHOD they are using and what file they are requesting. But for some reason it only outputs on the terminal and doesn't save it to logfile.txt...
package main
import (
"fmt"
"net/http"
"log"
"encoding/json"
"io/ioutil"
)
type Options struct {
Path string
Port string
}
func Log(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL)
handler.ServeHTTP(w, r)
})
}
func main() {
op := &Options{Path: "./", Port: "8001"}
data, _ := ioutil.ReadFile("./config.json")
json.Unmarshal(data, op)
http.Handle("/", http.FileServer(http.Dir(op.Path)))
err := http.ListenAndServe(":" + op.Port, Log(http.DefaultServeMux))
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
In your Log function, you are using fmt.Printf not fmt.Fprintf.
For example,
package main
import (
"fmt"
"log"
"net/http"
"os"
)
var logFile *os.File
func Log(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(logFile, "%s %s %s\n", r.RemoteAddr, r.Method, r.URL)
handler.ServeHTTP(w, r)
})
}
func main() {
var err error
logFile, err = os.Create("logfile.txt")
if err != nil {
log.Fatal("Log file create:", err)
return
}
defer logFile.Close()
}

Resources