-
First off, this package is amazing and truly appreciate the work that has been put into it. I'm using the generic style Endpoint struct {
// OpenAPI documentation fields.
Summary string `validate:"required"` // summary (name) for the endpoint.
OperationID string `validate:"optional"` // unique ID.
Description string `validate:"optional"` // longer description for the endpoint.
ExpectedErrors []error `validate:"optional"` // slice of expected errors the API can return.
Deprecated bool `validate:"optional"` // deprecated endpoint flag.
Tags []string `validate:"optional"` // additional tags used to group the endpoint.
// Handler action fields.
Method string `validate:"oneof=HEAD POST GET PUT DELETE"`
Path string `validate:"uri,startswith=/"`
Accepts []string `validate:"optional"` // immediate 415/406 return if Accept header doesn't match.
ContentTypes []string `validate:"optional"` // immediate 415/406 return if Content-Type header doesn't match.
Middlewares []func(next http.Handler) http.Handler `validate:"optional"`
Interactor usecase.Interactor `validate:"required"`
} It looks crazy, but I'm doing this so I can abstract out the creation of handlers for developers (and provide sensible defaults/validation/standard errors). Basically just "enterprise glue". Everything is working great, and I can use Since it's a field in I can PR a method/interface for |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Thank you for using this library, I'm happy you found it helpful! 🎉 Optional information can be retrieved from And then, interface assertion can be performed on an This whole trickery is done to keep Please check the following example: package main
import (
"context"
"fmt"
"github.com/swaggest/usecase"
"github.com/swaggest/usecase/status"
)
func main() {
u := usecase.NewInteractor(func(ctx context.Context, in string, out *int) error {
return nil
})
u.SetExpectedErrors(status.InvalidArgument, status.FailedPrecondition)
inspectExpectedErrors(u)
}
func inspectExpectedErrors(u usecase.Interactor) {
var hasErrors usecase.HasExpectedErrors
if usecase.As(u, &hasErrors) {
fmt.Println(hasErrors.ExpectedErrors()) // Use errors.
}
} |
Beta Was this translation helpful? Give feedback.
-
Ah, sorry, I misunderstood where you wanted to set errors. Interesting problem indeed. I'm not sure But if you have a good idea how to make this work, I don't mind to have such accessors. Conservatively, I would create a wrapper that overrides expected errors (and does not need to know about package main
import (
"context"
"fmt"
"github.com/swaggest/usecase"
"github.com/swaggest/usecase/status"
)
func main() {
u := usecase.NewInteractor(func(ctx context.Context, in string, out *int) error {
return nil
})
u.SetExpectedErrors(status.InvalidArgument, status.FailedPrecondition)
u2 := usecase.NewIOI(new(string), new(int), func(ctx context.Context, in, out interface{}) error {
return nil
})
u2.SetExpectedErrors(status.InvalidArgument, status.FailedPrecondition)
inspectExpectedErrors(addExpectedErrors(u, status.Canceled))
inspectExpectedErrors(addExpectedErrors(u2, status.Canceled))
}
// expectedErrors overrides expected errors in usecase.Interactor.
type expectedErrors struct {
errs []error
usecase.Interactor
}
func (ee expectedErrors) ExpectedErrors() []error {
return ee.errs
}
func addExpectedErrors(u usecase.Interactor, errs ...error) usecase.Interactor {
return usecase.Wrap(u, usecase.MiddlewareFunc(func(next usecase.Interactor) usecase.Interactor {
var hasErrors usecase.HasExpectedErrors
if usecase.As(u, &hasErrors) {
errs = append(errs, hasErrors.ExpectedErrors()...)
}
return expectedErrors{
Interactor: u,
errs: errs,
}
}))
}
func inspectExpectedErrors(u usecase.Interactor) {
var hasErrors usecase.HasExpectedErrors
if usecase.As(u, &hasErrors) {
fmt.Println(hasErrors.ExpectedErrors())
}
} |
Beta Was this translation helpful? Give feedback.
Ah, sorry, I misunderstood where you wanted to set errors. Interesting problem indeed.
I'm not sure
HasInfo/SetInfo
would help, becauseIOInteractor
andIOInteractorOf
are using value semantics, so they may be only accessible as copies and setters won't have expected effect. 🤔But if you have a good idea how to make this work, I don't mind to have such accessors.
Conservatively, I would create a wrapper that overrides expected errors (and does not need to know about
usecase.Info
).Please check this example: