How to log the HTTP return code with the chi router? - go

I use chi as my router and wrote a simple middleware that logs the request being made:
func logCalls(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Info().Msgf("%v → %v", r.URL, r.RemoteAddr)
next.ServeHTTP(w, r)
})
}
It works great but I am missing the HTTP return code.
The HTTP return code will obviously be available once all the routes are exhausted but at the same time I have to use my middleware before the routes.
Is there a way to hook it after the routing is done, and therefore have the return code I can log?

I think you need render from go-chi library.
https://github.com/go-chi/render/tree/v1.0.1
Example of usage is here:
https://github.com/go-chi/chi/blob/master/_examples/rest/main.go

Related

Why does http.NotFound() take the request as an argument?

The http.NotFound() method has the following signature:
func NotFound(w ResponseWriter, r *Request)
What is/was the purpose of the *Request argument?
Currently the value seems to be unused, and I find it hard to imagine what it might have been used for in the past.
This signature is the standard http.Handler signature.
NotFound obviously does not use the request:
// NotFound replies to the request with an HTTP 404 not found error.
func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
However, by sticking to the standard interface it interoperates with the rest of the http package:
http.HandleFunc("/favicon.ico", http.NotFound)

Go http response few headers

I'm want send to user alert if he type wrong password and return it to page were he type password. I'm making it like this
func sendJSONHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
http.ServeFile(w, r, "template/api/api.html")
} else if r.Method == "POST" {
r.ParseForm()
if r.Form["password"][0] == "apiPassword" {
j := struct {
Proxies []string
}{Proxies: code.UP.Proxy}
w.Header().Set("Access-Control-Allow-Origin", corsAddrSite)
json.NewEncoder(w).Encode(j)
} else {
// here is a problem
fmt.Fprintln(w, "<script>alert('Wrong Password')</script>")
http.ServeFile(w, r, "template/api/api.html")
}
}
}
But i'v get http: multiple response.WriteHeader calls error.
How to do it right?
You cannot write to the http.ResponseWriter more than once depending on the HTTP spec.
from the go docs https://golang.org/pkg/net/http/#ResponseWriter
To solve your issue, you could have the script tags inside the template file, or make a new template. You could also tailor the response by adding the alert script before you send it. Maybe with template files.
However a proper solution to this problem might be to have more logic in the actual html served, the front end should display a response based on the status code or response body.

How to set HTTP status code on http.ResponseWriter

How do I set the HTTP status code on an http.ResponseWriter (e.g. to 500 or 403)?
I can see that requests normally have a status code of 200 attached to them.
Use http.ResponseWriter.WriteHeader. From the documentation:
WriteHeader sends an HTTP response header with status code. If WriteHeader is not called explicitly, the first call to Write will trigger an implicit WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly used to send error codes.
Example:
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - Something bad happened!"))
}
Apart from WriteHeader(int) you can use the helper method http.Error, for example:
func yourFuncHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "my own error message", http.StatusForbidden)
// or using the default message error
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
http.Error() and http.StatusText() methods are your friends
w.WriteHeader(http.StatusInternalServerError)
w.WriteHeader(http.StatusForbidden)
full list here

How to dump both HTTP request and response in golang

I'm using gorilla web tool kit. There's a LoggingHandler available in the handler package, however it can only log the request data via the handler.
r := mux.NewRouter()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("This is a catch-all route"))
})
// This can only log the request, how can we log the response?
loggedRouter := handlers.LoggingHandler(os.Stdout, r)
http.ListenAndServe(":1123", loggedRouter)
httputil has the same feature available via DumpRequest(). In my case client is a browser, and I'm looking for a handler approach to log the response rather than logging it inside each and every handler.

How to pass along an http Request in golang?

I have a Request object in golang, and I would like to feed the contents of this object through a net.Conn as part of the task of a proxy.
I want to call something like
req, err := http.ReadRequest(bufio.NewReader(conn_to_client))
conn_to_remote_server.Write(... ? ... )
but I have no idea what I would be passing in as the arguments. Any advice would be appreciated.
Check out Negroni middleware. It let's you pass your HTTP request through different middleware and custom HandlerFuncs.
Something like this:
n := negroni.New(
negroni.NewRecovery(),
negroni.HandlerFunc(myMiddleware),
negroni.NewLogger(),
negroni.NewStatic(http.Dir("public")),
)
...
...
func myMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
log.Println("Logging on the way there...")
if r.URL.Query().Get("password") == "secret123" {
next(rw, r) //**<--------passing the request to next middleware/func**
} else {
http.Error(rw, "Not Authorized", 401)
}
log.Println("Logging on the way back...")
}
Notice how next(rw,r) is used to pass along the HTTP request
If you don't want to use Negroni, you can always look at it's implementation on how it passes the HTTP request to another middleware.
It uses custom handler which looks something like:
handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
Ref: https://gobridge.gitbooks.io/building-web-apps-with-go/content/en/middleware/index.html

Resources