In go-fiber docs they say:
As a rule of thumb, you must only use context values within the
handler, and you must not keep any references
is it OK if I passing around the context as a function argument like this:
func GetList(c *fiber.Ctx) error {
result, err := User.Search(c)
}
func Search(c *fiber.Ctx) (User, err) {
id := c.Params("id")
}
is that considered as a bad practice?
And I don't really understand this sentence:
As soon as you return from the handler, any values you have obtained
from the context will be re-used in future requests and will change
below your feet.
So if I have sent the response to the client the value of params will be reused? reused by whom? by me or by other people's request?
func GetList(c *fiber.Ctx) error {
id := c.Params("id") // 911
return c.SendString("Hello, World!")
}
so if the value of id was 911 does that mean other people request will also result in 911?
and what's the meaning of
will change below your feet
can anyone elaborate more easy for beginner like me to understand? thanks...
The actual context object can be reused by the framework after it calls your handler, so you cannot rely on its state after you return from the handler.
is it OK if I passing around the context as a function argument like this?
This is fine, as long as Search doesn't store the context elsewhere. If it just uses values from the context to conduct a search and then returns a result, that's fine.
So if I have sent the response to the client the value of params will be reused? reused by whom? by me or by other people's request?
The actual context object will be reused by the framework, while handling a later request.
and what's the meaning of "will change below your feet"?
If you don't follow the advice above, and instead keep references to the context after returning from your handler, the values in that context will change unexpectedly, since the framework is using that context for a new request.
Related
I'm trying to reduce the amount of http requests my discord bot is making.
It's reading from an API.
With the fetched data it updates an internal database and outputs the changes.
Thing is: that database is different for every server the bot is in, and that's where I'm using the go routines. But, some servers need to fetch the same data, here is where I want to reduce the http requests. Right now I'm making requests regardless if I've already fetched a character. I want to create some sort of data that could be shared between the go routines and before making a request search within this data.
I was advised to use mutex. I'm trying. Original question: Working with unbuffered channels in golang
I made a skeleton of the real code I've tried: https://play.golang.org/p/mt229ns1R8m
In this example master := make([][]map[string]interface{}, 0) is simulating the discord servers.
Chars and Chars2 would be the tracked chars for each individual server.
The char "Test" is mutual to both of them, so it should be fetched from the API only once.
It's outputing this:
[[map[Level:15 Name:Test] map[Level:150 Name:Test2]] [map[Level:1500 Name:Test3] map[Level:15 Name:Test]]]
------
A call would be made
A call would be made
A call would be made
A call would be made
Cache: [map[Level:150 Name:Test2] map[Level:15 Name:Test]]Cache: [map[Level:15 Name:Test] map[Level:1500 Name:Test3]]Done
I was expecting the output to be:
[[map[Level:15 Name:Test] map[Level:150 Name:Test2]] [map[Level:1500 Name:Test3] map[Level:15 Name:Test]]]
------
A call would be made
A call would be made
A call would be made
Cache: [map[Level:150 Name:Test2] map[Level:15 Name:Test] map[Level:1500 Name:Test3]]Done
But a new cache is being generated by every go routine. How can I fix this?
Thanks.
There are too many unknowns here for me to really write a proper design, but let's make a few notes:
Try not to use interface{} at all, if at all possible. In this case, it seems that it must be possible, though I'm not sure what the actual types will be.
Try to make your data as simple as possible, but no simpler. In this case, that probably means: have one data structure for "thing that talks to a Discord server" and a separate one for "thing that talks to the local database" (is this a caching database? if so, what are the criteria for invalidating a cache entry?). But if one "character" (whatever that is—apparently a string) can have different properties per Discord server, that means that your index into your local database is not just a character, but rather a pair of values: the string value itself plus a Discord-server-identifier.
This might give you a functional interface like this:
var cacheServer *CacheServer
func InitCacheServer() error {
cacheServer = ... // whatever it takes to initialize the cache server
}
(I've assumed lazy initialization of the cache server. If you can do up-front initialization, you can drop the next test below. Replace ValueType with the type of the result of a cached lookup of a name.)
func (DiscordServer ds) Get(name string) (ValueType, error) {
if cacheserver == nil {
if err := InitCacheServer(); err != nil {
return nil, err
}
}
// Do a cache lookup. Tell the cache server that if there
// is no entry, it should return a NoEntry error and we will
// fill the cache ourselves, so it should hold this slot as
// "will be filled, so wait for it".
slot, v, err := cacheServer.Lookup(name, ds.identity, CacheServer.IntentToFill)
if err == CacheServer.NoEntry {
// We have the slot held. Try to look up the right info
// directly in the Discord server, then cache it.
v, err = ds.UncachedGet(name)
// Tell cache server that this is the value, or that it should
// produce this error instead of NoCache.
cacheServer.FillSlot(slot, v, err)
}
}
You might only want to cache some error types, rather than all; that's another one of those design questions that needs an answer that I cannot provide here. There are other ways to do this that don't necessarily need a slot pointer return value, too; I've just chosen this one for this example.
Note that most of the "hard work" is now in the cache server, which definitely requires some fancy footwork. In particular you will want to lock the overall data structure for a little while, use that to find the correct slot, then hold the slot itself so that other users of the slot must wait, while releasing the overall lock so that other users of other entries need not wait. This introduces locking order constraints: be careful to avoid deadlock. One method that should work is:
type CacheServer struct {
lock sync.Mutex
data map[string]map[string]*Entry
// more fields
}
type Entry {
lock sync.Mutex
cachedValue ValueType
cachedError error
}
(You'll need some more types, like Intent—just two enumerated integers for now—below, and probably more fields in the above; this is just a skeleton.)
func (cs *CacheServer) Lookup(name, srv string, flags Intent) (*Entry, ValueType, error) {
cs.lock.Lock()
defer cs.lock.Unlock()
// first, look up the server - if it does not exist, create one
smap := cs.data[srv]
if smap == nil {
cs.data[server] = make(map[string]*Entry)
}
entry := smap[name]
if entry == nil {
// no cached entry - if this is a pure lookup, just error,
// but if not, make a locked entry
if flags == CacheServer.IntentToFill {
// make a new entry and return with it locked
entry = &Entry{}
smap[name] = entry
entry.lock.Lock() // and do not unlock
}
return entry, nil, NoEntry
}
entry.lock.Lock() // wait for someone to fill it, if needed
defer entry.lock.Unlock()
return nil, entry.cachedValue, entry.cachedError
}
You need a routine to fill and release the entry as well, but it's pretty simple. You could, if you choose, make this a method on the Entry type rather than on the CacheServer type, as at least in this particular prototype, there is no need to use the cache server data structures directly. If you start getting fancier with cache invalidation, though, it might be nice to have access to the CacheServer object.
Note: I've designed this so that you can do a cache lookup without an intent-to-fill, if that's useful. If not, there's no reason to bother with the Intent argument.
I am using err113 as part of golangci-lint.
It is complaining about ...
foo_test.go:55:61: err113: do not define dynamic errors, use wrapped static errors instead: "errors.New(\"repo gave err\")" (goerr113)
repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, errors.New("repo gave err")),
^
foo_test.go:22:42: err113: do not define dynamic errors, use wrapped static errors instead: "errors.New(\"oops\")" (goerr113)
repoMock.EXPECT().FindAll().Return(nil, errors.New("oops"))
^
What is best way to fix this ?
Quoting https://github.com/Djarvur/go-err113
Also, any call of errors.New() and fmt.Errorf() methods are reported
except the calls used to initialise package-level variables and the
fmt.Errorf() calls wrapping the other errors.
I am trying to get a idiomatic example for this.
Declare a package-level variables as suggested:
var repoGaveErr = errors.New("repo gave err")
func someFunc() {
repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, repoGaveErr)
}
Every call to errors.New allocates a new unique error value. The application creates a single value representing the error by declaring the package-level variable.
There are two motivations for the single value:
The application can compare values for equality to check for a specific error condition.
Reduce memory allocations (although probably not a big deal in practice)
The value io.EOF is a canonical example.
Since GO 1.13 you can define a new error type, wrap it and use it.
for example, if you want to return an "operation not permitted" + the operation.
you need to implement something like
var OperationNotPermit = errors.New("operation not permitted")
func OperationNotFoundError(op string) error {
return fmt.Errorf("OperationNotPermit %w : %s", OperationNotPermit, op)
}
then in your code, when you want to return the error,
return nil, OperationNotFoundError(Op)
Let's back to question case:
first, define the custom error and the wapper
var repoError = errors.New("repositoryError")
func RepositoryError(msg string) error {
return fmt.Errorf("%w: %s", repoError,msg)
}
then in your code,
repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, RepositoryError("YOUR CUSTOM ERROR MESSAGE"))
Since it hasn't been said before, you probably don't need to define package level errors for tests. Given the idea is to wrap errors so they can be compared and unwrapped in the caller, returning a dynamic error in a test is fine as long as the purposes of your test are served.
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
}
})
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.
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.