I want to use the same handler for multiple endpoints in a Go Gin app:
router.POST("/box/:boxID", controllers.AddUpdateBox)
router.PUT("/box/:boxID", controllers.AddUpdateBox)
router.PATCH("/box/:boxID", controllers.AddUpdateBox)
In the controller I want to find what is the request method (POST, PUT or PATCH).
func AddUpdateBox(c *gin.Context) {
}
How do I get the request method from the Gin context?
c.Request.Method
This member represents the method of the request
c.Request.Method
Struct http.Request on Package net/http has a property called Method that can be used to check the method on a currently running request.
Related
I have an issue to implement middleware i want to use negroni.Wrap function for validate user location and one for calling handler below is my route:
r.Handle("/users/{userID}", negroni.New(
negroni.HandlerFunc(validateTokenMiddleware),
negroni.Wrap(&userLocation),
negroni.Wrap(&userDetailHandler),
)).Methods("GET")
and &userLocation is object of an struct which contain db information, here when i request for handler then that time both wrap execute together. But i want execute &userlocation first and if any errors occur so next wrap should not be execute , how to resolve this issue.
Thanks.
Use a middleware having ServeHttp Method which will be called using userDetailHandler as receiver inside middleware. And pass your db struct in middleware as an argument . You should use single wrap.
r.Handle("/users/{userID}", negroni.New(
negroni.HandlerFunc(validateTokenMiddleware),
negroni.Wrap(userDetailHandler.Middleware(&userLocation)),
)).Methods("GET")
func (userDetailHandler *UserDetailHandler)Middleware(res http.ResponseWriter, req *http.Request, userLocation *userLocation){
// use your serve Http inside this
userDetailHandler.ServeHttp(res, req)
}
I need to manipulate response data in a middleware function. Assume I have product handlers and customer handlers. Product handler returns a list of products and customer returns a list of customers. In the middleware function, I want to convert these responses into ApiResponse struct.
type ApiResponse struct{
Data interface{}
Status ApiStatus{}
}
func someMiddleware(c *gin.Context){
//before handlers
c.Next()
//I need to access response and manipulate it
// apiResponse := ApiResponse{}
// apiResponse.Data = returnedData
// apiResponse.Status = ApiStatus{}
}
I don't want to fill ApiResponse in all handlerFunctions.
Probably a bit too late, but anyway.
The easiest way is usually to use Get and Set methods of gin.Context to pass data between your middleware and your handlers.
But if you really need to intercept responses, see my answer about logging response in gin. The only difference is what you do with intercepted response, but everything said there about intercepting it stays true.
I am using gin gonic to build a web application. I use https://github.com/gin-gonic/contrib/tree/master/sessions to handle session. Forexample, i set a integer value to session:
function Test(c *gin.Context){
session:= sessions.Default(c)
session.Set("mysession",123)
session.Save()
}
And in another controllers, i can get this session by session.Get("mysession").
But if i set map or struct. I only can get the session in the same controller. something wrong here??
You probably forgot to register it, when your app starts you need to have something like:
package main
import (
"encoding/gob"
"path/to/yourpackage"
func init() {
gob.Register(&yourpackage.YourStruct{})
}
You can look here http://www.gorillatoolkit.org/pkg/sessions for more information (gin-gonic uses gorilla sessions under the hood)
I'm using gorilla/context in a web app. The example in the docs looks like:
func MyHandler(w http.ResponseWriter, r *http.Request) {
//...
val := context.Get(r, foo.MyKey)
//...
}
How can I unit test a handler that works like this? The only way I've managed so far is to use the context package inside my tests. I'm thinking at the moment that I could inject a context parameter into the handler but then I'm not conforming to the HandlerFunc interface.
This is a classic cross-cutting concerns example.
You are using a 3rd party to magically handle input params for your unit under test. By that very definition, you are going to have to do some extra setup to prep the context for the state you want.
When it comes to Go http handlers (which the convention is to KISS it), you shouldn't need to "reach out of context" of your func to get extra data: keep all the data you need within your single func.
Personally, I try to avoid corrupting my handlers like this. I think I've only used gorilla's context once out of the dozens of big sites I've built. And that was basically to get around a cached response, just to keep the data refesh to the end user. Of which I simply ignored in my unit tests, as it was out-of-scrope of what I was testing.
Instead, I use middle-ware wrappers to setup the basics I want in my handles and modify the handler's signature accordingly.
caching
logging
authentication and authorization
json marshaling
context (e.g. expected User{} object loaded from DB)
...etc. I would create a middle-ware that wraps your handler when you register it with mux that uses gorilla/context to lookup your cookie or userid or something, hidrates that user object from cache, DB, redis, etc, and then calls your handler that would have a signature like:
func MyHandler(u User, p Page, w http.ResponseWriter, r *http.Request) {
// u is the User object loaded from middle-ware
// p is your global Page object... etc
}
That way, your unit tests inject only the items you need under test.
And you can integration test your middle-ware on a QA server with expected User and Page objects in a datastore.
The way my team does it is to add a name to the route handler and then in the tests we call that route by name.
This is how to add a route:
r.HandleFunc("/<route>", MyHandler).Methods("GET").Name("MyHandlerByName")
Then this is how to test it
r.Get("MyHandlerByName")
One way to test handles is modify the way in which they are created. for example, Creating a function that return a http.HandlerFunc, this function can have parameters. You can mock the values that you send to the function
Without parameters
func State() http.HandlerFunc {
return http.HandlerFunc(func(pResponse http.ResponseWriter, r *http.Request) {
// your code
})
}
With Parameters
func State(pParam1,pParam2,pParam3 ...) http.HandlerFunc {
return http.HandlerFunc(func(pResponse http.ResponseWriter, r *http.Request) {
// your code using pParam1,pParam2,pParam3
})
}
The mapping will be
http.HandleFunc("/State", State())
or
http.HandleFunc("/State", State(value1,value2,value3 ....))
Given a middleware function with a signature like:
func Middleware(handler http.Handler) http.Handler
How can I get response headers set and passed to it from a calling function?
First a HandlerFunc (the "base" or main server function) is initialized with some response headers. Then it is passed to and wrapped by the middleware function in the conventional manner.
How can I get the Response and its headers from the handler parameter?
I've tried a number of things but can't get at the header values.
Strictly speaking, you cannot. In priniple, the http.Handler is a function that is invoked for each request. As such, it is not bound to any specific request; it will be re-used for an arbitrary number of requests. As such, there is no way to retrieve HTTP request or response headers from an existing http.Handler object.
You can however, decorate the handler with your own middleware to access HTTP response headers that were set by the middleware function.
A middleware function as described in your question will typically be implemented like this:
func Middleware(originalHandler http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// call the original handler that is wrapped by this middleware
originalHandler.ServeHTTP(rw, req)
}
}
This function "decorates" the original http.Handler that is passed as a parameter into the middleware function by returning a new handler that implements custom logic and calls the original (wrapped) handler function at some point.
Within the new function, you can access the http.ResponseWriter object as usual to access the HTTP headers that were already set by the decorated handlers:
func Middleware(originalHandler http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// Add new headers to the response...
rw.Header().Set("X-My-Own-Header", "foo")
// ...or access data from the original request
fmt.Println(req.Header().Get("X-My-Request-Header")
// call the original handler that is wrapped by this middleware
originalHandler.ServeHTTP(rw, req)
// Access headers in the response object
rw.Header().Get("X-Header-Set-By-Middleware")
}
}