I have the following piece of code:
func GetUUIDValidator(text string) bool {
r, _ := regexp.Compile("/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/")
return r.Match([]byte(text))
}
But when I pass fbd3036f-0f1c-4e98-b71c-d4cd61213f90 as a value, I got false, while indeed it is an UUID v4.
What am I doing wrong?
Regex is expensive. The following approach is ~18x times faster than the regex version.
Use something like https://godoc.org/github.com/google/uuid#Parse instead.
import "github.com/google/uuid"
func IsValidUUID(u string) bool {
_, err := uuid.Parse(u)
return err == nil
}
Try with...
func IsValidUUID(uuid string) bool {
r := regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
return r.MatchString(uuid)
}
Live example: https://play.golang.org/p/a4Z-Jn4EvG
Note: as others have said, validating UUIDs with regular expressions can be slow. Consider other options too if you need better performance.
You can utilize satori/go.uuid package to accomplish this:
import "github.com/satori/go.uuid"
func IsValidUUID(u string) bool {
_, err := uuid.FromString(u)
return err == nil
}
This package is widely used for UUID operations: https://github.com/satori/go.uuid
In case you would be validating it as attribute of a struct, there is an awesome golang library straight from the Go called validator https://godoc.org/gopkg.in/go-playground/validator.v9 which you can use to validate all kinds of fields nested structures by provided built-in validators as well as complete custom validation methods. All you need to do is just add proper tags to the fields
import "gopkg.in/go-playground/validator.v9"
type myObject struct {
UID string `validate:"required,uuid4"`
}
func validate(obj *myObject) {
validate := validator.New()
err := validate.Struct(obj)
}
It provides structured field errors and other relevant data from it.
Related
I'm using this library to validate my Go struct.
https://pkg.go.dev/github.com/go-playground/validator/v10
How do I validate a field only if it's populated? For example, I have an optional phone number field in one of my structs. If the user has provided this value, I would like to validate it using E.164 format.
Phone string `validate:"e164"`
I searched for "optional" tag but couldn't find one.
As library documentation stated about Multiple Validators,
Multiple validators on a field will process in the order defined.
As #Flimzy described above, you can use omitempty to validate optional fields on structs, but omitempty should come first in the list. Otherwise it is validated and got an error.
Phone string `validate:"omitempty,e164"`
Simple proof of code is below, you can run on playground
package main
import (
"github.com/go-playground/validator/v10"
"log"
)
func main() {
sv := validator.New()
res := Response{}
err := sv.Struct(&res)
if err != nil {
log.Fatalln(err) // no error
}
res2 := Response2{}
err = sv.Struct(&res2)
if err != nil {
log.Fatalln(err) // error
}
}
type Response struct {
Phone string `validate:"omitempty,e164"`
}
type Response2 struct {
Phone string `validate:"e164,omitempty"`
}
Use the omitempty tag.
Phone string `validate:"e164,omitempty"`
I am starting to use Go and have found that to parse an html or xml document does not have a powerful tool by itself (excuse my ignorance if not).
The fact is that I have the following map (I converted the xml to a map using github.com/clbanning/mxj). It's a XML and HTML Clover report.
What I want is access to the different values: XML pastebin
My code:
xmlFile, err := os.Open(dir + "\\clover.xml")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
b, _ := ioutil.ReadAll(xmlFile)
defer xmlFile.Close()
fmt.Println("xmldata:", string(b))
// get all image tag values - []interface{}
mapvalue, merr := mxj.NewMapXml(b)
if merr != nil {
fmt.Println("merr:", merr.Error())
return
}
Even in the following way I can subdivide it:
sources, err := mapvalue.ValuesForKey("metrics")
if err != nil {
fmt.Println("err:", err.Error())
return
}
for i, src := range sources {
fmt.Println(i, src)
}
fmt.Println(sources[0])
It's that particular one I need. But now I can't access every one of the inner values.
map[-loc:459 -statements:71 -coveredmethods:14 -ncloc:307 -files:12
-conditionals:6 -coveredelements:45 -packages:8 -elements:110 -complexity:37 -classes:12 -coveredconditionals:1 -coveredstatements:30 -methods:33]
Is there an easier way to work with the XML and html I have in local?
I added the XML to map result: pastebin
GO has an xml parsing library https://golang.org/pkg/encoding/xml/
I have a runnable example here: https://play.golang.org/p/kVG3w4iu3Kl
package main
import (
"fmt"
"encoding/xml"
)
var rawXml = "<metrics coveredelements=\"45\" complexity=\"37\" loc=\"459\" methods=\"33\"/>"
type Metrics struct {
CoveredElements string `xml:"coveredelements,attr"`
Complexity string `xml:"complexity,attr"`
Loc string `xml:"loc,attr"`
Methods string `xml:"methods,attr"`
}
func main() {
data := &Metrics{}
xml.Unmarshal([]byte(rawXml), data)
fmt.Printf("%+v", data)
}
I think that you will find it much easier to work with structs.
I have found this utility to allow me to implement the necessary structures to parse the JSON answers (you can use a converter ). I hope you find it useful too:
https://mholt.github.io/json-to-go/
You can use a JSON/XML converter online like this: http://www.utilities-online.info/xmltojson/#.W1cSCNIzZPY.
For the rest I use the same what #Rossiar said in his comment.
Sorry if this question is a bit basic.
I am trying to use Golang interfaces to make the implementation of CRUD more dynamic.
I have implemented an interface as follows
type Datastore interface {
AllQuery() ([]interface{}, error)
ReadQuery() ([]interface{}, error)
UpdateQuery() ([]interface{}, error)
CreateQuery() ([]interface{}, error)
DestroyQuery() ([]interface{}, error)//Im not sure if the return value implementation is correct
}
That can be used with a multitude of models category Category,tag Tag.etc
It implements the methods indicative of the structs which represent the models in the app.
Here is the simplified handler/controller
func UpdateHandler(c handler.context) error {
p := new(models.Post)
return Update(p,c)
}
This is the function implementing the interface
func Update(data Datastore,c handler.context) error{
if err := c.Bind(data); err != nil {
log.Error(err)
}
d, err := data.UpdateQuery()
//stuff(err checking .etc)
return c.JSON(fasthttp.StatusOK, d)///the returned value is used here
}
This is the method I am using to query the database
func (post Post) UpdateQuery() ([]interface{}, error){
//run query using the
return //I dont know how to structure the return statement
}
How do I structure the interface above and the methods it implements so that I can return the result of the query back to the implementing function.
Please let me know if I need to add anything to the question or improve it I will try to do so promptly.
Thanks!
I think you should store the return value to a variable. Also make sure that this return value (result) is slice of interface.
If it's not then convert it by
v := reflect.ValueOf(s)
intf := make([]interface{}, v.Len())
In your case your UpdateQuery function might look like
func (post Post) UpdateQuery() (interface{}, bool) {
result,err := []Struct{}
return result, err
}
Demo :
https://play.golang.org/p/HOU56KibUd
Due to error handling in Go, I often end up with multiple values functions. So far, the way I have managed this has been very messy and I am looking for best practices to write cleaner code.
Let's say I have the following function:
type Item struct {
Value int
Name string
}
func Get(value int) (Item, error) {
// some code
return item, nil
}
How can I assign a new variable to item.Value elegantly. Before introducing the error handling, my function just returned item and I could simply do this:
val := Get(1).Value
Now I do this:
item, _ := Get(1)
val := item.Value
Isn't there a way to access directly the first returned variable?
In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the error (or raise a runtime panic if it still occurs).
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t *Template, err error) *Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.
Examples:
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)
Back to your case
IF you can be certain Get() will not produce error for certain input values, you can create a helper Must() function which would not return the error but raise a runtime panic if it still occurs:
func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}
But you should not use this in all cases, just when you're sure it succeeds. Usage:
val := Must(Get(1)).Value
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic Must() function:
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
This is available in github.com/icza/gog, as gog.Must() (disclosure: I'm the author).
Alternative / Simplification
You can even simplify it further if you incorporate the Get() call into your helper function, let's call it MustGet:
func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}
Usage:
val := MustGet(1).Value
See some interesting / related questions:
How to pass multiple return values to a variadic function?
Return map like 'ok' in Golang on normal functions
Yes, there is.
Surprising, huh? You can get a specific value from a multiple return using a simple mute function:
package main
import "fmt"
import "strings"
func µ(a ...interface{}) []interface{} {
return a
}
type A struct {
B string
C func()(string)
}
func main() {
a := A {
B:strings.TrimSpace(µ(E())[1].(string)),
C:µ(G())[0].(func()(string)),
}
fmt.Printf ("%s says %s\n", a.B, a.C())
}
func E() (bool, string) {
return false, "F"
}
func G() (func()(string), bool) {
return func() string { return "Hello" }, true
}
https://play.golang.org/p/IwqmoKwVm-
Notice how you select the value number just like you would from a slice/array and then the type to get the actual value.
You can read more about the science behind that from this article. Credits to the author.
No, but that is a good thing since you should always handle your errors.
There are techniques that you can employ to defer error handling, see Errors are values by Rob Pike.
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
return ew.err
}
In this example from the blog post he illustrates how you could create an errWriter type that defers error handling till you are done calling write.
No, you cannot directly access the first value.
I suppose a hack for this would be to return an array of values instead of "item" and "err", and then just do
item, _ := Get(1)[0]
but I would not recommend this.
How about this way?
package main
import (
"fmt"
"errors"
)
type Item struct {
Value int
Name string
}
var items []Item = []Item{{Value:0, Name:"zero"},
{Value:1, Name:"one"},
{Value:2, Name:"two"}}
func main() {
var err error
v := Get(3, &err).Value
if err != nil {
fmt.Println(err)
return
}
fmt.Println(v)
}
func Get(value int, err *error) Item {
if value > (len(items) - 1) {
*err = errors.New("error")
return Item{}
} else {
return items[value]
}
}
Here's a generic helper function with assumption checking:
func assumeNoError(value interface{}, err error) interface{} {
if err != nil {
panic("error encountered when none assumed:" + err.Error())
}
return value
}
Since this returns as an interface{}, you'll generally need to cast it back to your function's return type.
For example, the OP's example called Get(1), which returns (Item, error).
item := assumeNoError(Get(1)).(Item)
The trick that makes this possible: Multi-values returned from one function call can be passed in as multi-variable arguments to another function.
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
This answer borrows heavily from existing answers, but none had provided a simple, generic solution of this form.
I'm trying to get getObj() function will be more general and could
work with any type, not only User like in my code.
I was thinking in return a interface instead a defined struct, but I can't fit this
idea to my code, please could someone give me a hand with this?
Thanks in advance
type User struct {
FirstName string `bson:"first_name"`
LastName string `bson:"last_name"`
}
type Mbase struct {
coll *mgo.Collection
sess *mgo.Session
}
func (b *Mbase) getObj(attr string, val string) (res *User, err error) {
err = b.coll.Find(bson.M{attr: val}).One(&res)
if err != nil {
return
}
err = nil
return
}
You can do something like:
func (b *Mbase) GetObj(attr string, val string, result interface{}) error {
return b.coll.Find(bson.M{attr: val}).One(result)
}
Doesn't feel like the helper is doing much good, though. Find+One
itself is already generic. I'd also consider using bson.D{{attr, val}}
instead of bson.M if that's all you need.
Also, please consider asking questions in a single forum at a time.