Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to use fx.As and fx.ResultTags for the same Provider #1214

Open
Dan6erbond opened this issue Jun 12, 2024 · 1 comment
Open

Ability to use fx.As and fx.ResultTags for the same Provider #1214

Dan6erbond opened this issue Jun 12, 2024 · 1 comment

Comments

@Dan6erbond
Copy link

Is your feature request related to a problem? Please describe.

When annotating a provider function with fx.As() and fx.ResultTags() at the same time, Fx fails with an error:

2024-06-12T08:18:56.009Z        ERROR   fxevent/zap.go:59       start failed    {"error": "missing dependencies for function \"gitea.example.com/myproject/http/httpfx\".ConfigureServer (/workspaces/myproject/http/httpfx/module.go:20): missing type: http.Handler", "errorVerbose": "missing dependencies for function \"gitea.example.com/myproject/http/httpfx\".ConfigureServer\n\t/workspaces/carbase-backend/http/httpfx/module.go:20:\nmissing type:\n\t- http.Handler (did you mean to Provide it?)"}

Describe the solution you'd like
A clear and concise description of what you want to happen.

It would be great if I could do this:

var Module = fx.Module("chi",
	fx.Provide(
		fx.Annotate(
			NewRouter,
			fx.As(new(http.Handler)),
			fx.As(new(chi.Router)),
			fx.ResultTags(`name:"router"`),
		),
	),
)

Allowing parts of my application to expect the router while my core bootstrapping logic isn't coupled to Chi in any way and just accepts a router.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

At the moment I just ensure only one http.Handler is available in the DI.

Is this a breaking change?
We do not accept breaking changes to the existing API. Please consider if your proposed solution is backwards compatible. If not, we can help you make it backwards compatible, but this must be considered when we consider new features.

I don't think so.

Additional context
Add any other context or screenshots about the feature request here.

The code above should give a good overview of what I'm trying to achieve, as I want to decouple my HTTP server from whichever router I end up using and just attach the http.Handler to it.

@JacobOaks
Copy link
Contributor

Hey @Dan6erbond thanks for the issue.

With the way that ResultTags works, the code you showed is applying the router name to both the http.Handler and the chi.Router. Named types are considered entirely separate from their unnamed counterparts from Fx's perspective. That's why you see Fx complaining about not having an unnamed http.Handler:

missing dependencies <...> missing type: http.Handler.

For now, you'll have to workaround this by either doing two returns and annotating them independently like:

func NewRouter() (chi.Router, http.Handler) {
	/* logic to create the router */
	return router, router
}

fx.Provide(
	fx.Annotate(
 		NewRouter,
		fx.ResultTags(`name:"router"`),
	)
)

Or if you can't change NewRouter, you can sort of manually annotate using "constructors" to add the 2nd representation.

fx.Provide(
	NewRouter, // let's say this returns a *routerImpl
	func(r *routerImpl) http.Handler { return r },
	fx.Annotate(
		func(r *routerImpl) chi.Router { return r },
		fx.ResultTags(`name:"router"`),
	),
)

This does unfortunately expose the underlying type to the container. If you can provide the exact definitions of chiRouter and the return types of NewRouter I can help you with an example to avoid this if that's an isue.

This is admittedly not very ergonomic and is an unfortunate consequence of how annotations work, which is why #899 is on our radar. Nested annotations would help a little bit allowing you to do something like this to keep the handler unnamed but the router named:

fx.Provide(
	fx.Annotate(
		fx.Annotate(
			NewRouter,
			fx.As(new(http.Handler)),
		),
	fx.As(new(chi.Router)),
	fx.ResultTags(`name:"router"`),
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants