Friday, February 24, 2017

tips on Golang Programing

tipsgolang

Tips for Go Programing

If you are working on No Network Environment, and you don't have a Golang book. How to keep working on when you forget how to use the command.

Go to the location you installed golang.

cd /usr/local/go/src

There are a lot of code on it.
Choose a command you want to know, select

grep select *

You will find a lot of example, and you might know how to write a correct code.
Of course, if you forget how to define function that how to return a channel. Try it.

grep chan *

You will find the answer.

Wednesday, February 15, 2017

golang http middleware ( net/http and httprouter+alice)

gomiddleware

Golang Middleware (net/http and httprouter+alice)

That's talk about Golang standard lib net/http and my favorate lib httprouter + alice.

Thanks for this blog, it really inspire me alot.

https://libraries.io/go/github.com%2Fmontanaflynn%2Fgo-middleware

Use Standard net/http

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

func enableCORS(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
        if r.Method == "OPTIONS" {
            w.WriteHeader(200)
        }
        handler.ServeHTTP(w, r)
    })
}

func logRequests(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        now := time.Now()
        method := r.Method
        path := r.URL.Path
        fmt.Printf("%v %s %s\n", now.Format("Jan 2, 2006 at 3:04pm (MST)"), method, path)
        handler.ServeHTTP(w, r)
    })
}

func delay(handler http.Handler, length string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        timeout, err := time.ParseDuration(length)
        if err != nil {
            log.Println("Could not parse delay length, skipping delay.")
            handler.ServeHTTP(w, r)
        }
        time.Sleep(timeout)
        handler.ServeHTTP(w, r)
    })
}
func helloWorld(w http.ResponseWriter, r *http.Request) {
    fmt.Println("haha in world ha")
    w.Write([]byte("Hello world!"))
}
func helloWorld1(str string) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("haha in world1 ha")
        w.Write([]byte("Hello world!"))
    })
}
func helloWorld2(str string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("haha in world2 ha")
        w.Write([]byte("Hello world!"))
    })
}
func main() {
    //app := delay(logRequests(enableCORS(http.HandlerFunc(helloWorld))), "1s")
    app := delay(logRequests(enableCORS(http.HandlerFunc(helloWorld1("5")))), "5s")
    //app := helloWorld2("5")
    http.ListenAndServe(":8080", app)

There are three types of calling helloWord(x) function.

  1. with middleware but without passing paramteters, said helloWorld

    app := delay(logRequests(enableCORS(http.HandlerFunc(helloWorld))), "1s")

  2. with middleware and with passing paramteters, said hellowWorld1

    app := delay(logRequests(enableCORS(http.HandlerFunc(helloWorld1("5")))), "5s")

  3. without middleware with parameter, said helloWorld2

    app := helloWorld2("5")

One can check the method related to its function call.

Httprouter and Alice

package main

import (
    "encoding/json"
    "fmt"
    "github.com/coreos/etcd/client"
    "github.com/gorilla/context"
    "github.com/julienschmidt/httprouter"
    "github.com/justinas/alice"
    "github.com/pborman/uuid"
    "io"
    "net/http"
    "os"
    "time"
)

func tokenHandler(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("into middle recover")

        // put process here
        token := r.Header.Get("Auth-Token")
        fmt.Println(token)
        if token == "powertoken" {
            next.ServeHTTP(w, r)
        }
        err := getTokenExist(kAPI, token)
        if err == nil {
            next.ServeHTTP(w, r)
        } else {

            http.Error(w, http.StatusText(401), 401)
        }
        // error oocured
    }
    return http.HandlerFunc(fn)
}

func wrapHandler(h http.Handler) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        context.Set(r, "params", ps)
        h.ServeHTTP(w, r)
    }
}
func getInfoHandler(w http.ResponseWriter, r *http.Request) {

    w.Header().Set("Content-Type", "application/json")
    //a := make(map[string]string)
    a := map[string]interface{}{}
    a["test"] = "haha"
    jsonString, _ := json.Marshal(a)
    //w.WriteHeader(200)
    w.Write(jsonString)
}

func getInfoHandler1(str string) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("I am here with str:", str)
        w.Header().Set("Content-Type", "application/json")
        //a := make(map[string]string)
        a := map[string]interface{}{}
        a["test"] = "haha"
        jsonString, _ := json.Marshal(a)
        //w.WriteHeader(200)
        w.Write(jsonString)
    })
}
func ttHandler(aa string) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        fmt.Println("in tt handler", aa)

        w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
        http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)

    }
}

func startWeb() {

    commonHandlers := alice.New(loggingHandler, tokenHandler, middlewareGenerator("foo", "foo2"))
    router := httprouter.New()
    router.GET("/version", wrapHandler(commonHandlers.ThenFunc(getInfoHandler)))
    router.GET("/version1", wrapHandler(commonHandlers.ThenFunc(getInfoHandler1("haha"))))

    aa := "strrrrr"
    router.GET("/tt", ttHandler(aa))
    http.ListenAndServe(":8080", router)
}

func main() {
    //println("start web")
    go startWeb()
    fmt.Println("start over")
    var input string
    fmt.Scanln(&input)
}

There are three points here.

  1. How to pass parameters to alice middleware said middlewareGenerator

    alice.New(loggingHandler, tokenHandler, middlewareGenerator("foo", "foo2"))

  2. How to pass parameters to httprouter and alice chain said getInfoHandler1

    router.GET("/version1", wrapHandler(commonHandlers.ThenFunc(getInfoHandler1("haha"))))

  3. How to pass parameters to httprouter said ttHandler

    router.GET("/tt", ttHandler(aa))

One can check the method related to its function call.

Conclustion

Now you have different way to deal with different situations.
Just copy and paste it.
Keep in mind, it's all about golang's wrap function and return value.