Go rest handler views every request as GET - go

So basically I am trying to build this simple REST API, and I have this createCartHandler that every time I call it using postman it looks like the request method is GET. So no matter how I do the request, r.Method will be GET. Do you know what could cause this?
Also, if I do the request using something like cURL (curl -XPOST'http://localhost:8080/v1/create') it looks like it doesn't even view the request, like it is pointless.
type Service struct {
cache *lru.Cache
}
func (s *Service) createCartHandler() http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Method)
....
})
}
func main() {
cache, err := lru.New(1024)
if err != nil {
log.Panicf("Faild to create cache: %v", err)
}
svc := &Service{
cache: cache,
}
...
mux := http.NewServeMux()
mux.Handle("/v1/create/", svc.createCartHandler())
address := hostport
...
log.Print("Listening on ", hostport)
// When running on docker mac, can't listen only on localhost
panic(http.ListenAndServe(address, mux))
}

Related

Serve multiple handlers with httptest to mock multiple requests

I've googled all over for this but can't find anything.
I have a struct that takes in a http.Client and it sends several GET requests. In my tests I want to mock the responses so it's not sending real requests.
Currently I've figured out how to only serve 1 request, like this:
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
file, err := os.Open("./testdata/1.html")
if err != nil {
t.Error(err)
}
bytes, err := ioutil.ReadAll(file)
if err != nil {
t.Error(err)
}
w.Write(bytes)
}))
ts.Client() // Now I can inject this client into my struct.
So once that response is mocked out and the http client is performs a new request, my tests are sending out real requests after that.
How do I allow for several handlers so I can mock several responses upon calling http.Client.Get(...)?
Since the original question uses httptest.NewServer - you can register a ServeMux on the httptest.Server function, and then you can add several routes to that mux:
mux := http.NewServeMux()
mux.HandleFunc("/someroute/", func(res http.ResponseWriter, req *http.Request) {
...do some stuff...
})
mux.HandleFunc("/someotherroute/", func(res http.ResponseWriter, req *http.Request) {
...do other stuff...
})
ts := httptest.NewServer(mux)
defer ts.Close()
ServeMux.Handle can be used to setup a server to handle multiple requests like in this example.
package main
import (
"log"
"net/http"
)
const addr = "localhost:12345"
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/hello", HandleHello)
// other handlers can be assigned to separate paths
log.Printf("Now listening on %s...\n", addr)
server := http.Server{Handler: mux, Addr: addr}
log.Fatal(server.ListenAndServe())
}
func HandleHello(w http.ResponseWriter, r *http.Request) {
log.Printf("Hello!")
}
But to be honest you probably just want to abstract the http.Client behind an interface that you've created, and then stub that with a test implementation that returns exactly what you want. By doing this you avoid the overhead of http communication in your tests.

How can I combine Go middleware pattern with error returning request handlers?

I am familiar with the Go middleware pattern like this:
// Pattern for writing HTTP middleware.
func middlewareHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Our middleware logic goes here before executing application handler.
next.ServeHTTP(w, r)
// Our middleware logic goes here after executing application handler.
})
}
So for example if I had a loggingHandler:
func loggingHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Before executing the handler.
start := time.Now()
log.Printf("Strated %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
// After executing the handler.
log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
})
}
And a simple handleFunc:
func handleFunc(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`Hello World!`))
}
I could combine them like this:
http.Handle("/", loggingHandler(http.HandlerFunc(handleFunc)))
log.Fatal(http.ListenAndServe(":8080", nil))
That is all fine.
But I like the idea of Handlers being able to return errors like normal functions do. This makes error handling much easier as I can just return an error if there is an error, or just return nil at the end of the function.
I have done it like this:
type errorHandler func(http.ResponseWriter, *http.Request) error
func (f errorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := f(w, r)
if err != nil {
// log.Println(err)
fmt.Println(err)
os.Exit(1)
}
}
func errorHandle(w http.ResponseWriter, r *http.Request) error {
w.Write([]byte(`Hello World from errorHandle!`))
return nil
}
And then use it by wrapping it like this:
http.Handle("/", errorHandler(errorHandle))
I can make these two patterns work separately, but I don't know how I could combine them. I like that I am able to chain middlewares with a library like Alice. But it would be nice if they could return errors too. Is there a way for me to achieve this?
I like this pattern of HandlerFuncs returning errors too, it's much neater and you just write your error handler once. Just think of your middleware separately from the handlers it contains, you don't need the middleware to pass errors. The middleware is like a chain which executes each one in turn, and then the very last middleware is one which is aware of your handler signature, and deals with the error appropriately.
So in it's simplest form, keep the middleware you have exactly the same, but at the end insert one which is of this form (and doesn't execute another middleware but a special HandlerFunc):
// Use this special type for your handler funcs
type MyHandlerFunc func(w http.ResponseWriter, r *http.Request) error
// Pattern for endpoint on middleware chain, not takes a diff signature.
func errorHandler(h MyHandlerFunc) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Execute the final handler, and deal with errors
err := h(w, r)
if err != nil {
// Deal with error here, show user error template, log etc
}
})
}
...
Then wrap your function like this:
moreMiddleware(myMiddleWare(errorHandler(myhandleFuncReturningError)))
That means this special error middleware can only ever wrap your special function signature, and come at the end of the chain, but that's fine. Also I'd consider wrapping this behaviour in your own mux to make it a little simpler and avoid passing error handlers around, and let you build a chain of middleware more easily without having ugly wrapping in your route setup.
I think if you're using a router library, it needs explicit support for this pattern to work probably. You can see an example of this in action in a modified form in this router, which uses exactly the signatures you're after, but handles building a middleware chain and executing it without manual wrapping:
https://github.com/fragmenta/mux/blob/master/mux.go
The most flexible solution would be like this:
First define a type that matches your handler signature and implement ServeHTTP to satisfy the http.Handler interface. By doing so, ServeHTTP will be able to call the handler function and process the error if it fails. Something like:
type httpHandlerWithError func(http.ResponseWriter, *http.Request) error
func (fn httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := fn(w, r); err != nil {
http.Error(w, err.Message, err.StatusCode)
}
}
Now create the middleware as usual. The middleware should create a function which returns an error if it fails or calls the next in the chain on success. Then convert the function to the defined type something like:
func AuthMiddleware(next http.Handler) http.Handler {
// create handler which returns error
fn := func(w http.ResponseWriter, r *http.Request) error {
//a custom error value
unauthorizedError := &httpError{Code: http.StatusUnauthorized, Message: http.StatusText(http.StatusUnauthorized)}
auth := r.Header.Get("authorization")
creds := credentialsFromHeader(auth)
if creds != nil {
return unauthorizedError
}
user, err := db.ReadUser(creds.username)
if err != nil {
return &httpError{Code: http.StatusInternalServerError, Message: http.StatusText(http.StatusInternalServerError)}
}
err = checkPassword(creds.password+user.Salt, user.Hash)
if err != nil {
return unauthorizedError
}
ctx := r.Context()
userCtx := UserToCtx(ctx, user)
// we got here so there was no error
next.ServeHTTP(w, r.WithContext(userCtx))
return nil
}
// convert function
return httpHandlerWithError(fn)
}
Now you can use the middleware as you would use any regular middleware.
The output of a middleware, by definition, is an HTTP response. If an error occurred, either it prevents the request from being fulfilled, in which case the middleware should return an HTTP error (500 if something unexpectedly went wrong on the server), or it does not, in which case whatever happened should be logged so that it can be fixed by a system administrator, and the execution should continue.
If you want to achieve this by allowing your functions to panic (although I would not recommend doing this intentionally), catching this situation and handling it later without crashing the server, there is an example in this blog post in section Panic Recovery (it even uses Alice).
From what I understand you wanted to chain your errorHandler function and and combine them in your loggingHandler.
One way to do this is using a struct passing it to your loggingHandler as parameter like this :
func loggingHandler(errorHandler ErrorHandler, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Call your error handler to do thing
err := errorHandler.ServeHTTP()
if err != nil {
log.Panic(err)
}
// next you can do what you want if error is nil.
log.Printf("Strated %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
// After executing the handler.
log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
})
}
// create the struct that has error handler
type ErrorHandler struct {
}
// I return nil for the sake of example.
func (e ErrorHandler) ServeHTTP() error {
return nil
}
and in the main you call it like this :
func main() {
port := "8080"
// you can pass any field to the struct. right now it is empty.
errorHandler := ErrorHandler{}
// and pass the struct to your loggingHandler.
http.Handle("/", loggingHandler(errorHandler, http.HandlerFunc(index)))
log.Println("App started on port = ", port)
err := http.ListenAndServe(":"+port, nil)
if err != nil {
log.Panic("App Failed to start on = ", port, " Error : ", err.Error())
}
}

Is there 'middleware' for Go http client?

I would like to ask if we can create 'middleware' functions for Go http client? Example I want to add a log function, so every sent request will be logged, or add setAuthToken so the token will be added to each request's header.
You can use the Transport parameter in HTTP client to that effect, with a composition pattern, using the fact that:
http.Client.Transport defines the function that will handle all HTTP requests;
http.Client.Transport has interface type http.RoundTripper, and can thus be replaced with your own implementation;
For example:
package main
import (
"fmt"
"net/http"
)
// This type implements the http.RoundTripper interface
type LoggingRoundTripper struct {
Proxied http.RoundTripper
}
func (lrt LoggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, e error) {
// Do "before sending requests" actions here.
fmt.Printf("Sending request to %v\n", req.URL)
// Send the request, get the response (or the error)
res, e = lrt.Proxied.RoundTrip(req)
// Handle the result.
if (e != nil) {
fmt.Printf("Error: %v", e)
} else {
fmt.Printf("Received %v response\n", res.Status)
}
return
}
func main() {
httpClient := &http.Client{
Transport: LoggingRoundTripper{http.DefaultTransport},
}
httpClient.Get("https://example.com/")
}
Feel free to alter names as you wish, I did not think on them for very long.
I worked on a project that had similar requirement so I built a middleware pipeline library that allows setting multiple middleware to the http client. You can check it out here.
Using the library, you would solve this in the following way
type LoggingMiddleware struct{}
func (s LoggingMiddleware) Intercept(pipeline pipeline.Pipeline, req *http.Request) (*http.Response, error) {
body, _ := httputil.DumpRequest(req, true)
log.Println(fmt.Sprintf("%s", string(body)))
/*
If you want to perform an action based on the response, do the following
resp, err = pipeline.Next
// perform some action
return resp, err
*/
return pipeline.Next(req)
}
transport := pipeline.NewCustomTransport(&LoggingMiddleware{})
client := &http.Client{Transport: transport}
resp, err := client.Get("https://example.com")
if err != nil {
// handle err
}
fmt.Println(resp.Status)
I wrote a small tutorial/library to do just that https://github.com/HereMobilityDevelopers/mediary
Here is some basic usage example:
client := mediary.Init().AddInterceptors(dumpInterceptor).Build()
client.Get("https://golang.org")
func dumpInterceptor(req *http.Request, handler mediary.Handler) (*http.Response, error) {
if bytes, err := httputil.DumpRequestOut(req, true); err == nil {
fmt.Printf("%s", bytes)
//GET / HTTP/1.1
//Host: golang.org
//User-Agent: Go-http-client/1.1
//Accept-Encoding: gzip
}
return handler(req)
}
There is also an explanation here https://github.com/HereMobilityDevelopers/mediary/wiki/Reasoning
Good idea! Here is a simple implementation of HTTP service middleware in Go.
Usually a simple http service framework is to register a bunch of routes, and then call different logics to process them according to the routes.
But in fact, there may be some unified processing involving almost all routes, such as logs, permissions, and so on.
So it is a good idea to engage in intermediate preprocessing at this time.
Define a middleware unit:
package main
import (
"net/http"
)
// AdaptorHandle middleware func type
type AdaptorHandle func(w http.ResponseWriter, r *http.Request) (next bool, err error)
// MiddleWareAdaptor router middlewares mapped by url
type MiddleWareAdaptor struct {
URLs map[string][]AdaptorHandle
}
// MakeMiddleWareAdaptor make a middleware adaptor
func MakeMiddleWareAdaptor() *MiddleWareAdaptor {
mwa := &MiddleWareAdaptor{
URLs: make(map[string][]AdaptorHandle),
}
return mwa
}
// Regist regist a adaptor
func (mw *MiddleWareAdaptor) Regist(url string, Adaptor ...AdaptorHandle) {
for _, adp := range Adaptor {
mw.URLs[url] = append(mw.URLs[url], adp)
// mw.URLs[url] = adp
}
}
// Exec exec middleware adaptor funcs...
func (mw *MiddleWareAdaptor) Exec(url string, w http.ResponseWriter, r *http.Request) (bool, error) {
if adps, ok := mw.URLs[url]; ok {
for _, adp := range adps {
if next, err := adp(w, r); !next || (err != nil) {
return next, err
}
}
}
return true, nil
}
Then wrap the route processing function with a middleware entry:
func middlewareHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// before call handler
start := time.Now()
do, _ := mwa.Exec(r.URL.Path, w, r) // exec middleware
// call next handler
if do {
log.Println("middleware done. next...")
next.ServeHTTP(w, r)
} else {
log.Println("middleware done.break...")
}
// after call handle
log.Printf("Comleted %s in %v", r.URL.Path, time.Since(start))
})
}
mux.Handle("/", middlewareHandler(&uPlusRouterHandler{}))
type uPlusRouterHandler struct {
}
func (rh *uPlusRouterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
...
}
Finally, register the middleware you need:
mwa = MakeMiddleWareAdaptor() // init middleware
mwa.Regist("/", testMWAfunc, testMWAfunc2) // regist middleware
...
func testMWAfunc(w http.ResponseWriter, r *http.Request) (bool, error) {
log.Println("I am Alice Middleware...")
log.Printf("Started %s %s", r.Method, r.URL.Path)
return true, nil
}
func testMWAfunc2(w http.ResponseWriter, r *http.Request) (bool, error) {
log.Println("I am Ben Middleware...")
return false, nil // return false,break follow-up actions.
}
This can be achieved using closure functions. It's probably more clear with an example:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/hello", logged(hello))
http.ListenAndServe(":3000", nil)
}
func logged(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("logging something")
f(w, r)
fmt.Println("finished handling request")
}
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "<h1>Hello!</h1>")
}
credit goes to: http://www.calhoun.io/5-useful-ways-to-use-closures-in-go/

Middleware using Alice and HttpRouter

I can't seem to work out how to use middleware and Http Router properly together.
My code is:
type appContext struct {
db *mgo.Database
}
func main(){
c := appContext{session.DB("db-name")}
commonHandlers := alice.New(context.ClearHandler, basicAuthHandler)
router := NewRouter()
router.Post("/", commonHandlers.ThenFunc(c.final))
http.ListenAndServe(":5000", router)
}
The final middleware is:
func (c *appContext) final(w http.ResponseWriter, r *http.Request) {
log.Println("Executing finalHandler")
w.Write([]byte("TESTING"))
}
but I want my basicAuthHandler to be part of the commonHandlers. It also needs the context so that I can query the db.
I have tried this:
func (c *appContext) basicAuthHandler(w http.ResponseWriter, r *http.Request) {
var app App
err := c.db.C("apps").Find(bson.M{"id":"abcde"}).One(&app)
if err != nil {
panic(err)
}
//do something with the app
}
but I get the error undefined: basicAuthHandler. I understand why I'm getting the error but I don't know how to avoid it. How can I provide the context to the basicAuthHandler and still use it in the commonHandlers list for Alice?
Your middleware needs to have the signature
func(http.Handler) http.Handler
This way your middleware is wrapping handlers, not just providing a final handler. You need to accept an http.Handler, do whatever processing needs to be done, and call ServeHTTP on the next handler in the chain. Your basicAuthHandler example could look like this:
func (c *appContext) basicAuthHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var app App
err := c.db.C("apps").Find(bson.M{"id": "abcde"}).One(&app)
if err != nil {
panic(err)
}
h.ServeHTTP(w, r)
})
}
(though you don't want to panic in your app, and should provide a better error response)

Golang net/http and Gorilla: run code before handler

Is it possible using the net/http package and/or any of the gorilla libraries to make some code execute on EVERY URL before going to the handler? For example, to check if a connection is coming from a black listed IP address?
Create a handler that invokes another handler after checking the IP address:
type checker struct {
h http.Handler
}
func (c checker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if blackListed(r.RemoteAddr) {
http.Error(w, "not authorized", http.StatusForbidden)
return
}
c.h.ServeHTTP(w, r)
}
Pass this handler to ListenAndServe instead of your original handler. For example, if you had:
err := http.ListenAndServe(addr, mux)
change the code to
err := http.ListenAndServe(addr, checker{mux})
This also applies to all the variations of ListenAndServe. It works with http.ServeMux, Gorilla mux and other routers.
If you want to use the default muxer, which i find is common, you can create middleware like so:
func mustBeLoggedIn(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
// Am i logged in?
if ...not logged in... {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
// Pass through to the original handler.
handler(w, r)
}
}
Use it like so:
http.HandleFunc("/some/priveliged/action", mustBeLoggedIn(myVanillaHandler))
http.ListenAndServe(":80", nil)

Resources