How to add new route to autogenerate resources? - go

please help me, I want add new route/func to generate resource (etc. users).
app.Resource("/users", UsersResource{})
I found func addRoute, but doesn't work.
func (a *App) addRoute(method string, url string, h Handler) *RouteInfo { ...
My idea is something like this.
"/users/handleSomething/idOfUser"
Right now i have only this func:
List(Context)
Show(Context)
New(Context)
Create(Context)
Edit(Context)
Update(Context)
Destroy(Context)
Thx for your time and help :)
PS: Sorry for my English :(

If you want additional routes you can use the methods GET,POST,PUT, ... that are defined on the *App type. (https://gobuffalo.io/en/docs/routing#supported-http-methods)
To handle dynamic path segments in the route you can use named parameters. (https://gobuffalo.io/en/docs/routing#named-parameters)
Example:
app.PATCH("/users/handleSomething/{id}", handleSomethingHandler)
To retrieve the value of the named parameter you can use c.Param("id") where c is the buffalo context passed in to your handler.

Related

Two structs having same receiver function implementations, how to remove the duplications

I have two structs that are having same receiver function implementations:
type A struct {
name string
// other fields
}
type B struct {
name string
// other fields
}
type AA struct {
resource A
}
func (a *AA) Get() string {
// process something with a.resource.name
return a.resource.name
}
type BB struct {
resource B
}
func (b *BB) Get() string {
// process something with b.resource.name
return b.resource.name
}
type I interface {
Get() string
}
both structs AA and BB have Get function, in order to satisfy the interface I, this might be a dumb question, but I dont know how I can simplify them to remove the duplications of two Get functions, tried:
having a generic struct and embedded in A & B - cant do this due
to json serializations in the system I use.
embedded AA in BB and calling AA.Get - wont work since name is inside B instead of A
Combine AA and BB with both fields like resourceA and resourceB - this complicates the Get function, since then it needs to handle
create a non-receiver function and use it for both AA and BB - this can work but since there are quite some fields I need, not just name, so the function will end up with quite many parameters.
I cant stop feeling there should be an easier way, and also trying/googling a way to simplify it, but non of them seems to work, could someone point me some directions or hints?
much appreciated!
[UPDATE]
I'm trying to create a Kubernetes operator, which has some CRDs (Custom Resource Definitions), and since I create a generic controller that just take the CRDs and calling their functions (that's why I have interface), but I found I need to implement functions that are exactly the same, like GetName, GetObject, or some functions that manipulate the data and get back the results, and they're all the same across those CRD structs.
I've decided to just create a function that takes required parameters, and reuse the function across the structs, thanks for all the comments.
If you have other suggestions, please feel free to comment or suggest, thanks!

How to use multiple parameters in query router

everybody!
The question is:
How to write multiple parameters in query router, so I can write one, two or more parameters like this:
/applications/filter/?date=today
/applications/filter/?status=true
/applications/filter/?date=today&status=true
I tried this, but it does not work for single parameter, only for two:
router.HandleFunc("/applications/filter/", authMiddle.RequiresLogin(authContrl.FilterDateStatus())).
Queries("date", "{date}", "status", "{status}").Methods("GET")
This is a little bit confusing in the beginning, but your route is always the same here:
/applications/filter/?date=today
/applications/filter/?status=true
/applications/filter/?date=today&status=true
It is always /applications/filter/.
In that case you just need to map one route here. The handle func receives the request. Inside the request you can parse the url.
https://play.golang.org/p/op49nTJSlCP
Putting all together it could look like:
router.HandleFunc("/applications/filter/",func(w http.ResponseWriter,r *http.Request){
// in production you should handle the errors!
// I am just skipping this to keep the example simple
u, _ := url.Parse(r.URL)
v := u.Query()
if _,ok := v[date]; ok {
// do something with dae
}
})

Iterate through all PostForm values Gin Gonic

Is there an easy way to list / iterate through all post values using Gin Gonic? (Go)
I have tried:
c.Request.ParseForm()
for key, value := range c.Request.PostForm {
log.Printf("POST %v = %v",key,value)
}
But this shows no values, however when I test the values directly from context:
log.Printf("POST email = %v", c.PostForm("email")
It outputs fine.
What I'm trying to do is to map all post values into a gin.H{} context, so that upon failure I can pass the posted values back into the .HTML template context and have them prefilled (along with my error message). Best I've found is manually wiring each POST value to the gin.H{} map, but for a large form these seems verbose and not ideal.
We also needed something like #BadPirate describes so if anyone need for gin 1.6.2
func register(c *gin.Context){
c.MultipartForm()
for key, value := range c.Request.PostForm {
log.Printf("%v = %v \n",key,value)
}
}
Thanks #BadPirate and #phoet for the info.
Issue here was the form (not shown) was a multipart form. ParseForm does not parse multipart forms, and thus, no data. The fix is to call ParseMultipartForm instead. Thanks to #phoet for pointing at the method in Gin Gonic for PostForm (which calls ParseMultipartForm for you, and does so automatically), which helped lead me to the answer.

What are these method parameters called in Swift?

I'm just taking my first steps with Swift and after having worked with things like PHP, Ruby, JavaScript and Python, this is all totally new to me.
So, I have code like this:
class DerpController: NSURLConnectionDelegate, NSURLConnectionDataDelegate {
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse) {
println("response received")
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
println("data received")
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
println("request finished")
}
}
What are these things called: didReceiveResponse, didReceiveData? Are they some kind kind of message identifier or what?
And is func connection one overloaded method or are there actually two that are identified by these "didReceive..." names?
didReceiveResponse is an external parameter name. response and data are local parameter names.
This means that the first function is called with myDerpController.connection(url, didReceiveResponse:response). But within the body of the function you refer to the parameter as response.
The second function is a typo, and should be didReceiveData
These are delegate methods defined by NSURLConnectionDataDelegate, which is a protocol you have adopted.
In Swift, a parameter can have both an internal (parameter, local) name and an external (argument, caller) name. The internal name (response:, data:) is entirely up to you; the name provided by the docs and by code completion is just a "serving suggestion". The external name, however, needs to match the selector name by which Objective-C (or any other caller) will seek it. The method is called e.g. connection:didReceiveData: so you must use an external name didReceiveData for the second parameter in order to be called.
You also asked (irrelevantly) about overloading. Overloading by type is legal in Swift but not in Objective-C; the latter uses names (selectors) alone. You're biting off a lot at once here because you've chosen to start with an example involving heavy interplay between Swift and Objective-C, to understand which you really need to know at least the rudiments of both languages.

golang mux, routing wildcard & custom func match

I'm using the mux package which seems to work quite well except that it doesn't seem to support complex routes or at least I don't get it how it does.
I have several routes as following:
router := mux.NewRouter()
router.HandleFunc("/{productid}/{code}", product)
router.HandleFunc("/{user}", userHome)
router.HandleFunc("/search/price", searchPage)
So I have two questions:
How can I define a wildcard route such /search/price/* so that a request such /search/price/29923/rage/200/color=red can match it ?
Is it possible to add custom conditions to an existing route ? e.g. if the route is /{productid}/{code} and function x returns true , use this handlerTrue, if it returns false use handlerFalse.
I've tried to add something like .MatcherFunc(myfunction(ip)bool) to the route but it complains that the router has no such method.
Currently I'm handling the 'custom' conditions inside the handler.
You can use regexps. Something like
router.HandleFunc(`/search/price/{rest:[a-zA-Z0-9=\-\/]+}`, searchPage)
That way, rest will just capture everything, so in your example rest would be 29923/rage/200/color=red. You will need to parse that in your code.
You probably want some like optional arguments, though.
router.HandleFunc(`/search{price:(\/price\/[0-9]+)?}{rage:(\/rage\/[0-9]+)?}{color:(\/color=[a-z]+)?}`, searchPage)
After that, you get vars price = "/price/29923", rage = "/rage/200" and color = "/color=red", that you still need to parse, but its easier, and you get to control which parameters are valid. It works as expected if you skip some parameter, eg. /search/price/29923/color=red will just give an empty rage variable, but still match.
I don't quite get your second question.
I'm not quite sure you need a "wildcard" route at all: you just need a route with multiple parameters:
/search/price/{price}/rage/{id}/color will work, noting that query strings don't need to be included in the matcher (you access those via request.URL.Query, whereas you access the mux variables via mux.Vars. You can also use regex to narrow down the accepted parameters.
It will also help to differentiate your user and product routes, perhaps by prefixing them with /user/{id} and /products/{id}/{code} (particularly for semantics).
As far as MatcherFunc goes, you need to make sure your function uses the same signature as MatcherFunc (which is a type): func MatchIPAddresses(*http.Request, *RouteMatch) bool would solve it. You can access the IP address via the Request struct by checking r.RemoteAddr or r.Header.Get("X-Forwarded-For") if you expect to be behind a proxy. I typically check both if one is empty ("").
i.e. (rough; you can clean this up a bit!)
func MatchIPAddresses(r *http.Request, rm *RouteMatch) bool {
if r.RemoteAddr == 8.8.8.8 {
return true
} else if r.Header.Get("X-Forwarded-For") == 8.8.8.8 {
return true
}
return false
}
To use a custom MatcherFunc with gorilla mux, you need to ensure that your matcher is actually of type mux.MatcherFunc. This is because MatcheFunc is not an interface type
// From mux/route.go line 303
// MatcherFunc is the function signature used by custom matchers.
type MatcherFunc func(*http.Request, *RouteMatch) bool
So you have to do something like:
var myMatcher mux.MatcherFunc = func(request *http.Request, match *mux.RouteMatch) bool {
// Your custom logic
return trueOrFalse
}
// You can then use it on your route like this.
router := mux.NewRouter()
router.HandleFunc("/{productid}/{code}", product).MatcherFunc(myMatcher)
With chi as router you can do the following:
Since the regex never matches a slash / you can simply match with *
e.g. for /search/price/29923/rage/200/color=red
router.Get(`/search/price/*`, priceHandler)
func DashboardFilesHandler(w http.ResponseWriter, r *http.Request) {
path := myhandler.UrlParam(r, "*")
// path will be '29923/rage/200/color=red'
}
See also: https://godoc.org/github.com/go-chi/chi
A placeholder with a name followed by a colon allows a regular
expression match, for example {number:\d+}. The regular expression
syntax is Go's normal regexp RE2 syntax, except that regular
expressions including { or } are not supported, and / will never be
matched. An anonymous regexp pattern is allowed, using an empty string
before the colon in the placeholder, such as {:\d+}
The special placeholder of asterisk matches the rest of the requested
URL. Any trailing characters in the pattern are ignored. This is the
only placeholder which will match / characters.

Resources