Lansana Camara
Lansana Camara

Reputation: 9873

Override interface's function callback arguments

I am using a package that has a Router interface, and I have created my own app-specific Router interface that wraps the third party package.

Everything is working well, however one of the methods is throwing a compilation error:

controllers/auth.go:52:17: cannot use func literal (type func(router.Router)) as type func(chi.Router) in argument to c.router.Group

This is the interface of the third party package (chi):

type Router interface {
    // ...

    // Group adds a new inline-Router along the current routing
    // path, with a fresh middleware stack for the inline-Router.
    Group(fn func(r Router)) Router

    // ...
}

This is my wrapper interface:

type Router interface {
    chi.Router

    // Custom methods...
}

My usage of the Group function is like so:

type AuthController struct {
    router router.Router
    // ...
}

func (c *AuthController) SetRoutes() {
    c.router.Group(func(r router.Router) {
        r.Use(middleware.Anyone)

        r.Post("/auth/register", c.Register)
        r.Post("/auth/login", c.Authenticate)
        r.Post("/auth/token/refresh", c.RefreshToken)
    })

    c.router.Group(func(r router.Router) {
        r.Use(middleware.Authorized)

        r.Get("/auth/ping", c.Ping)
        r.Post("/auth/logout", c.Logout)
    })
}

Why is it screaming at my function callbacks argument type? My wrapper router.Router implements the chi.Router interface, so it should work fine shouldn't it? Am I misunderstanding how Go works here?

Upvotes: 0

Views: 759

Answers (2)

Adrian
Adrian

Reputation: 46423

I can see how this can be confusing so I will try to break it down. You have this method:

Group(fn func(r Router)) Router

This method takes a function as a parameter. That function must have a specific signature:

func(r Router)

That is, it takes a single argument of type chi.Router and has no return values. However, when you call it:

c.router.Group(func(r router.Router) { /***/ }

You're passing in a function of the wrong signature; your function signature is:

func(r router.Router)

That's not the signature required by the method you're calling, so it won't compile. It doesn't matter if router.Router implements chi.Router; the parameter (a func(router.Router)) passed is not of the expected type (a func(chi.Router)).

This may seem silly at first - after all, any router.Router must implement chi.Router. But, think about it: that method, Group, is expecting to receive a function, to which it can pass any chi.Router. That means it can pass a chi.Router which does not implement router.Router. If it were to accept your function, it would break type safety, and what in Go is meant to be a compile-time error (the error you're getting, in fact) would become a run-time error. Basically, by passing a function with a different (and more strict) argument type, you're expecting a guarantee which that method never offered.

Upvotes: 2

Andy Schweig
Andy Schweig

Reputation: 6749

The parameter types aren't the same, so the function type doesn't match what's expected, even though your interface includes the interface from the other package (the type has to match exactly). You need to have your functions take a chi.router and then use a type assertion, i.e., myRouter := r.(Router), to convert to your type.

Upvotes: 2

Related Questions