How do I extract a string from an interface{} variable in Go? - go

I'm new to the Go language.
I'm making a small web application with Go, the Gorilla toolkit, and the Mustache template engine.
Everything works great so far.
I use hoisie/mustache and gorilla/sessions, but I'm struggling with passing variables from one to the other. I have a map[string]interface{} that I pass to the template engine. When a user is logged in, I want to take the user's session data and merge it with my map[string]interface{} so that the data becomes available for rendering.
The problem is that gorilla/sessions returns a map[interface{}]interface{} so the merge cannot be done (with the skills I have in this language).
I thought about extracting the string inside the interface{} variable (reflection?).
I also thought about making my session data a map[interface{}]interface{} just like what gorilla/sessions provides. But I'm new to Go and I don't know if that can be considered best practice. As a Java guy, I feel like working with variables of type Object.
I would like to know the best approach for this problem in your opinion.
Thanks in advance.

You'll need to perform type assertions: specifically this section of Effective Go.
str, ok := value.(string)
if ok {
fmt.Printf("string value is: %q\n", str)
} else {
fmt.Printf("value is not a string\n")
}
A more precise example given what you're trying to do:
if userID, ok := session.Values["userID"].(string); ok {
// User ID is set
} else {
// User ID is not set/wrong type; raise an error/HTTP 500/re-direct
}
type M map[string]interface{}
err := t.ExecuteTemplate(w, "user_form.tmpl", M{"current_user": userID})
if err != nil {
// handle it
}
What you're doing is ensuring that the userID you pull out of the interface{} container is actually a string. If it's not, you handle it (if you don't, you'll program will panic as per the docs).
If it is, you pass it to your template where you can access it as {{ .current_user }}. M is a quick shortcut that I use to avoid having to type out map[string]interface{} every time I call my template rendering function.

Related

2 parameters invoke lambda aws from golang

i want to send the 2 parameters a lambda needs in order to work and it basically needs the value i want to search and as a second parameter the field where to find that value.
Now with no problem i've been able to access some other lambdas with that only need one parameter with a code like this.
func (s *resourceService) GetProject(ctx context.Context, name string) projectStruct {
payload, err := json.Marshal(name)
util.Logger.Debugf("Payload",payload)
invokeOutput, err := s.lambdaSvc.Invoke(ctx, &lambda.InvokeInput{
FunctionName: &s.getProject,
InvocationType: "RequestResponse",
Payload: payload,
})
if err != nil {
panic(err.Error())
}
var project projectStruct
err = json.Unmarshal(invokeOutput.Payload, &project)
if err != nil {
panic(err.Error())
}
util.Logger.Debugf("Invocation output [%v]", invokeOutput)
return project
}
now with 2 parameters i've had a lot of problems and tried a LOT of different approaches starting for adding another Payload value, creating a string with the 2 values and marshal it, marshaling both parameters and try and add them as the payload, even append both marshaled bytes array but i've been incapable of sending 2 parameters as the payload
Do you know the right way to do so? Please Help
Lambda functions only take one Payload. In V1 of the AWS SDK, InvokeInput takes one []byte parameter expressing JSON, as you already know.
You can structure your one Json Payload to carry a list. Looking at your example, Payload could look something like
["name","name"]
You could change your signature like so:
func (s *resourceService) GetProject(ctx context.Context, names []string) projectStruct
json.Marshal can handle marshaling a slice just as well as the elements within the slice, so the remaining code doesn't need to change.
Of course the receiving function must agree about the schema of the data it's being passed. If you wish to change from a string to a list of strings, that will be a breaking change. For that reason, Json schemas typically use named values instead of scalars.
[{ "Name": "Joan"},{"Name":"Susan"}]
You can add Age and Address without breaking the receiving function (though of course, it will ignore the new fields until you program it to ignore them).
Take time to Get to know JSON - it's a simple and expressive encoding standard that is reliably supported everywhere. JSON is a natural choice for encoding structured data in Go because JSON integrates well with Go's with structures, maps, and slices.

Map to store generic type functions in Go

I am trying to create a Map with String and functions as key and Value. It works if all functions are of same signature but my requirement is to store functions of different signature in the same map. Is this possible in Go?
package main
import "fmt"
func main() {
functions := buildFunctions()
f := functions["isInValid"]
// f("hello")
}
func buildFunctions() map[string]func() bool {
functions := map[string]func() bool{
"isInValid": isInValid,
"isAvailable": isAvailable,
}
return functions
}
func isInValid(s string) bool {
fmt.Println("Invalid ", s)
return true
}
func isAvailable(s string, s1 string) bool {
return true
}
https://play.golang.org/p/ocwCgEpa_0G
Go is a strongly typed language. So, it's not possible the way, it is possible with, say python. But just like python, once you do this, you loose the benefit of compile time error checks, and your runtime error checking has to be full-proof.
Here's what you can do:
Use map[string]interface{} type for your function map, which enables you to store anything. But then you are responsible to correctly type assertion at the time of calling. Problem is that, in most cases, if while calling a function, you could know the type of function, may be you might not need a map in the first place.
Use a map[string]string or map[string]interface{} as the argument, and return type in all the functions that are supposed to go into this map. Or at least put all the variable arguments into this map.
eg.
map[string](func (name string, age int, other_attributes
map[string]interface{}) (map[string]interface{}, error))
But again, each function call should provide the correct arguments, and there should also be checks inside the functions, to see (with non-panic version of map lookup), if the parameters are correctly provided, if not, you can return a custom error like ErrInvalidParametersPassed. (playing the role of an interpreter). But you will still have lesser chances of messing up, compared to first option. As the burden of type assertion will be on the function implementation, and not the caller. Caller just needs to fetch it's required values, which it anyways needs to know about.
But yet, best option would be to redesign your actual solution in a way, so that it can be done without going this road. As #bereal suggested in comments, it's good to have separate maps if possible, or maybe use a superset of arguments if they aren't too different, or too many. If there are just a few arguments, even switch case could be clean enough. Look for ways that cheat/bypass compile time checks, when you are truly convinced that there is no other elegant way.

Convert slice of errors to a slice of structs in golang

I'm using the Golang validate library to do some input error checking as part of an API (a silly demo API for learning purposes).
When one performs the validation a slice of errors is returned. In reality, the slice is made up of the validate library's struct BadField, which looks like this:
type BadField struct {
Field string
Err error
}
func (b BadField) Error() string {
return fmt.Sprintf("field %s is invalid: %v", b.Field, b.Err)
}
I'd like to pass around a more-specific slice, so rather than []error I would like have []BadField so that I can access the Field value.
So far I can't find a way of casting/converting from one to the other. Maybe there isn't one (due to the nature of go and slices). Maybe there's a package that will do this for me.
My initial implementation
The way I've come up with is to loop through the slice and cast each element individually.
errors := valueWithBadStuff.Validate()
validationErrors := make([]validate.BadField, len(errors))
for _, err := range errors {
validationError, ok := err.(validate.BadField)
if !ok {
panic("badarghfiremyeyes") // S/O purposes only
}
validationErrors = append(validationErrors, validationError)
}
Which feels kinda long for something "simple" but perhaps there's a more go idiomatic way? Or a nicer way?
For background, my intention (at the moment) is to take the slice of validation errors and pipe it back to the client as an array of JSON objects with the Field name and the error message (i.e. for a fictional age field: ["field_name": "age", "Cannot be less than 0"])
Just after the loop above I do more conversion to generate a slice of structs that are tagged with json that will actually go the client. The extra conversion may be duplication and pointless but, right now, it's purely a learning piece and I'll probably refactor it in an hour or two.
There's not really a "nicer" way of doing this. To convert a slice you have to basically do what you've already discovered.
If you are simply returning these errors to a client, you could probably avoid the need to typecast this at all.
Implement the JSON Marshaler interface and you can make your type will automatically output the JSON in the format you desire. For example, for the format you gave above this would be:
func (e BadField) MarshalJSON() ([]byte, error) {
return json.Marshal([]string{"field_name",e.Field,e.Err.Error()})
}
I suspect however that you would probably rather have a response something like:
[
{
"field":"age",
"error":"msg1"
},
{
"field":"name",
"error":"msg2"
}
]
To do this, you could simply add the JSON tags to the struct definition, e.g.
type BadField struct {
Field string `json:"field"`
Err error `json:"error"`
}
This would mean calling json.Marshal on a slice of []error which contains BadField instances would result in the JSON above.
It might be helpful to read more about JSON & Go
PS Consider if you want your methods to be value or pointer receivers

Passing different structs to a function (GO)?

I have a function like the following for querying a mongo database:
func findEntry(db, table string, entry *User, finder *bson.M) (err error) {
c := mongoSession.DB(db).C(table)
return c.Find(finder).One(entry)
}
I'd like to reuse the function for structs other than "User", by passing in a pointer to any instantiated struct object - just not quite sure of the proper semantics to do this. I think that I should be able to do this by making the 'entry' parameter an interface{} and then I'd need to use reflection to 'cast' it back to the original struct so the One() function call could properly fill in the struct on the call? Is there a 'better' way to accomplish this (please no flaming about lack of generics, I'm just looking for a practical solution using best practices).
Use this function:
func findEntry(db, table string, entry interface{}, finder bson.M) error {
c := mongoSession.DB(db).C(table)
return c.Find(finder).One(entry)
}
and call it like:
var user User
err := findEntry("db", "users", &user, bson.M{"name": "John"})
The type information for user is passed through findEntry to the One method. There's no need for reflection or a "cast" in findEntry.
Also, use bson.M instead of *bson.M. There's no need to use a pointer here.
I created an example on the playground to show that the type information is passed through findEntry.

Golang gorilla sessions preserving form data after redirect

From logic point of view I am trying to preserve partial form data between redirects for better user experience so user won't have to fill entire form again, just the part that was invalid.
From programing point of view I am trying to save request.PostForm data structure in gorilla session's flashes. The only thing I manage to retrieve after redirect is string representation of memory address like this [0xc2001c8b10].
Here is the part where I save flashes data after validation error (request.ParseForm() was executed before this):
session, _ := store.Get(request, "test")
session.AddFlash(err.Error(), "messages")
session.AddFlash(request.PostForm, "form_data")
session.Save(request, response)
http.Redirect(response, request, "/", http.StatusFound)
return
Also I tried registering structure with gob without effect:
func init() {
gob.Register(&url.Values{})
}
Form values are in lower case, eg. "first_name", "last_name" if that could have any influence on this behavior.
Please keep in mind that I successfully manage to retrieve "messages" after redirect, only problem I have is with structural data.
Am I doing something wrong or is there maybe another approach to fill partial forms after redirect that I am not aware of?
Your problem is that you're working with values of type interface{}, which is the generic type
and used when there can be more than one type. This is the case for gorilla's session.Flashes()
method as it can return arbitrary user data (whatever you put in).
You can reproduce what you're experiencing with this code (on play):
type MyData struct {
X int
}
// Simulate Flashes() from gorilla, which returns a slice of interface{} values.
func Flashes() []interface{} {
x := &MyData{2}
// Convert x to type interface{}
interfaceValue := interface{}(x)
// Put converted x into a slice of type []interface{}
return []interface{}{interfaceValue}
}
func main() {
// See that [0xSOMETHING] is printed
fmt.Println("Some data:", Flashes())
}
When running this program you will see output like this:
Some data: [0xc010000000]
This is the same you're experiencing. The reason for this is that fmt.Println does
not step through all levels of abstraction of pointers and interfaces and stops at
a certain level unless you tell it to print everything. So if you use
fmt.Printf("Some data: %#v\n", Flashes())
you will indeed see your data:
Some data: []interface {}{(*main.MyData)(0xc010000000)}
What you have to do to access the data is to match the resulted data for the type
you're expecting. You have to do a type assertion (example on play):
func main() {
value := Flashes()[0]
v, ok := value.(*MyData)
if ok {
fmt.Println("Some data:", v)
} else {
fmt.Println("Oh no, there's something else stored than expected")
}
}
In the example above the first flash returned by Flashes() is used and asserted to be
of type *MyData. If it is indeed this type, then it's value is printed to the console.
Otherwise an error message (albeit not a good one) is printed to the console.
After asserting a variable of being some type, the asserted value is of the asserted
type. That is the v in the example above is of type *MyType.

Resources