Compare dynamic error message using Error.Is function - go

I have a dynamic error message for example
metadata.name: invalid value "test-value"
"test-value" will be dynamic, and I need to do something if this error pattern appears
How to check the errors pattern with Error.Is function?

You say your error has a dynamic message. I think you mean that you're defining a type that satisfies the error interface. (If you're using fmt.Errorf instead though, you should define a type for this use case).
type invalidValueError struct {
value string
}
func (e *invalidValidError) Error() string {
return fmt.Sprintf("invalid value %q", e.value)
}
You can check whether any given error has this type using errors.As. This will match not only the error itself, but any errors it's wrapping.
if ive := (*invalidValueError)(nil); errors.As(err, &ive) {
// got an *invalidValueError
}
Avoid matching the text of error messages if at all possible. They can change on different systems or in different locales, and they're generally not covered by compatibility promises.

Related

"Generate resource" command with "--skip-model" flag results in faulty resource

Description
Just started using Buffalo, trying out all the beautiful features :)
I'm having an issue however with the "generate resource" command in combination with the "--skip-model" flag. When this flag is used, all the generated functions ("List", "Show", "Create", "Update" and "Destroy") are created fully in lowercase. The struct however that is also generated refers to "buffalo.Resource" and contains these functions with the first letter in uppercase, resulting in a resource that doesn't work.
Steps to Reproduce the Problem
Use generate resource command with "--skip-model" flag: buffalo g r todo --skip-model.
Run the application using: buffalo dev.
Navigate to "http://127.0.0.1:3000/todoes"; verify that you get an error saying "runtime error: invalid memory address or nil pointer dereference".
Verify in the generated file that "todoes.go" contains the generated functions ("List", "Show", "Create", "Update" and "Destroy") fully in lowercase, while the generated struct called "TodoesResource" refers to "buffalo.Resource" and contains these functions with the first letter in uppercase.
Expected Behavior
I expected the generated functions to have the first letter in uppercase, matching the names in "buffalo.Resource" and resulting in the response "Todo#list" when navigating to "http://127.0.0.1:3000/todoes" (after starting the application). This is the case when you don't use the "--skip-model" flag, so I'm not sure why this would behave differently when you do use this flag.
Actual Behavior
The generated functions ("List", "Show", "Create", "Update" and "Destroy") are fully in lowercase, while the generated struct called "TodoesResource" refers to "buffalo.Resource" and contains these functions with the first letter in uppercase. This results in the error "runtime error: invalid memory address or nil pointer dereference" when navigating to "http://127.0.0.1:3000/todoes" (after starting the application).
Suggested solution(s)
I'm not able to create a pull request (as I get the error "Permission to gobuffalo/buffalo.git denied" when trying to publish a branch), but I think there are two possible solutions to this issue:
Preferred solution
Modifying the file "genny/resource/templates/standard/action/resource-name.go.tmpl" to change the code below:
// {{$a.String}} default implementation.
func (v {{$.opts.Name.Resource}}Resource) {{$a.String}}(c buffalo.Context) error {
return c.Render(http.StatusOK, r.String("{{$.opts.Model.Proper}}#{{$a.String}}"))
}
And change this to:
// {{$a.Pascalize}} default implementation.
func (v {{$.opts.Name.Resource}}Resource) {{$a.Pascalize}}(c buffalo.Context) error {
return c.Render(http.StatusOK, r.String("{{$.opts.Model.Proper}}#{{$a.Pascalize}}"))
}
Alternative solution
Modifying the file "genny/resource/actions.go" to change the code below:
func actions(opts *Options) []name.Ident {
actions := []name.Ident{
name.New("list"),
name.New("show"),
name.New("create"),
name.New("update"),
name.New("destroy"),
}
if opts.App.AsWeb {
actions = append(actions, name.New("new"), name.New("edit"))
}
return actions
}
And change this to:
func actions(opts *Options) []name.Ident {
actions := []name.Ident{
name.New("List"),
name.New("Show"),
name.New("Create"),
name.New("Update"),
name.New("Destroy"),
}
if opts.App.AsWeb {
actions = append(actions, name.New("New"), name.New("Edit"))
}
return actions
}
This was a bug and is currently being fixed. Also see: https://github.com/gobuffalo/buffalo/issues/2023.

linter err113: do not define dynamic errors, use wrapped static errors instead

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.

Golang error control on parameters when calling a function with reflection

I'm trying to call a function using reflection based on it's name.
I first recover the function with
f := reflect.ValueOf(s).MethodByName(name)
I do error control on the function name by checking if "f" is valid with
if !f.IsValid() {
return errors.New("There is no function with that name")
}
And finally I perform the call with
f.Call(inputs)
My challenge is that inputs depends on the user, and sometimes they can put too many parameters, too little or invalid types.
IE:
2019/01/04 16:47:54 http: panic serving [::1]:53662: reflect: Call using string as type int
How can I control that the inputs are valid before performing the call?
Maybe there is a way to recover the expected inputs in my method and check them against the provided ones?

How to cast a promise error to a custom type?

Hej, I have this piece of code
BsFirebase.Auth.signInWithEmailAndPassword(
Firebase.auth,
~email=self.state.email,
~password=self.state.password,
)
|> Js.Promise.then_(_user => {
// ...
})
|> Js.Promise.catch((error) => {
// ...
})
|> ignore;
In the catch, the error field includes a field code that I can use to have more details about the error.
I'm trying to write a wrapper function to cast the error to a "custom" type but I have no idea how to do it.
So far I have (thanks Jared)
type firebaseError = {"code": int, "message": string}; /* etc. */
external unsafeCeorceToFirebaseError: Js.Promise.error => firebaseError = "%identity";
How can I add extra check to be sure the code property exists in the error ?
One way would be to treat the data structure as JSON, if that's appropriate, and use a JSON decoding library like bs-json since those are designed to deal with unknown or unreliable data structures.
Alternatively, you can type each field as a Js.Nullable.t and test them individually upon use.
Although if you can avoid using promise errors for error handling that would be much preferred, as it's not a type safe way of doing it. Use the result type instead and treat promise errors like exceptions.

how to pass different types to a function

I have two golang functions, doing exactly same thing, one takes input a slice and the other takes a map as input. I want to combine this into one function, to avoid duplication.
func DoSomething([]data) {
//do something.
}
func DoSomething(map[string]data) {
//do something.
}
Combined function may look like:
func DoSomethingNew (param type) {
//param could be map or slice
}
I want to know if it is possible to pass different types to same function in golang and how. I googled but couldn't find anything relevant.
You can use interfaces Go Playground
func F(data interface{}) {
switch data.(type){
case []int:
fmt.Println("Slice")
fmt.Println(data)
case map[string]int:
fmt.Println("Map")
fmt.Println(data)
}
fmt.Println()
}
where you actually check for the type and do something based on the type.
There are several ways you could do this, but the simple way would be to make it so DoSomethingNew accepts the interface{} type. Inside of the method you would then do a type switch or in this case with only two options, perhaps just one type assertion, followed by the other, returning error if both fail. Another option would be to have both as arguments and check for nil inside the function with a similar if, else-if, else pattern to handle the error if the input is of neither types you're looking for. To make your code more safe you could move to a more strict interface than the empty one which all types implement. You could also do some method chaining or even implement the method with using the types themselves as the receiving type. Here's an example that shows a few of the ideas; https://play.golang.org/p/_v2AyFjGzv

Resources