go-module-router Migration

go-module-router is replaced by go-foundation for new projects. The old module can stay available for existing users, but new work should use the Foundation packages below.

Package Map

go-module-router go-foundation
pkg/transport/http app, app/web
pkg/core.Container app/di
pkg/core.Binder core/bind, core/reflectutil
pkg/swagger core/openapi
pkg/transport/action app/actions
pkg/transport/relay core/relay
pkg/logger core/logger

HTTP

Old:

r := router.New()
r.Provide("Users", users)
r.Register(&GetUser{})
r.Listen(":8080")

New:

a := app.New()
a.Provide("Users", users)
RegisterFoundation(a)

if err := a.Listen(":8080"); err != nil {
	log.Fatal(err)
}

Handlers keep the same shape:

type GetUser struct {
	_     struct{}     `method:"GET" path:"/users/{id}"`
	ID    string       `path:"id"`
	Users *UserService `inject:"Users"`
}

func (h *GetUser) Handle(ctx context.Context) (any, error) {
	return h.Users.Get(ctx, h.ID)
}

Actions

Old:

type SaveAction struct {
	Meta     core.Pattern `action:"file.save" keys:"ctrl+s"`
	Document *Document
}

func (a *SaveAction) Handle(ctx context.Context) (any, error) {
	return a.Document.Save()
}

New:

type SaveAction struct {
	_        struct{}  `action:"file.save" keys:"ctrl+s"`
	Document *Document `inject:"Document"`
	Name     string    `json:"name"`
}

func (a *SaveAction) Handle(ctx context.Context) (any, error) {
	return a.Document.Save(a.Name)
}

Standalone:

router := actions.New()
router.Provide("Document", doc)
if err := router.RegisterDefinition(actionDefinition); err != nil {
	log.Fatal(err)
}

result, err := router.Dispatch(ctx, "file.save", map[string]any{
	"name": "notes.md",
})

Through app:

a := app.New()
a.Provide("Document", doc)
RegisterFoundation(a)

result, err := a.Dispatch(ctx, "file.save", map[string]any{
	"name": "notes.md",
})

Key bindings:

result, err := a.DispatchKey(ctx, "ctrl+s", map[string]any{
	"name": "notes.md",
})

Optional events:

bus := events.New()
a.UseActionEvents(bus)

Use UseAsyncActionEvents when event handlers should run through the async event queue.

Relay

go-module-router had a relay transport that read relay:"topic" tags from handler structs. Foundation keeps relay registration explicit:

r := manager.New()

manager.Register[SendNotification](r, "notifications.send", func(ctx context.Context, payload SendNotification) error {
	return notifications.Send(ctx, payload.UserID, payload.Message)
})

ready, err := r.Start(ctx)
if err != nil {
	log.Fatal(err)
}
<-ready

Use this form for new code. It keeps the payload type visible at registration and avoids a second dispatch layer around the broker.

OpenAPI

Old:

doc, err := swagger.Build("API", "1.0.0", &GetUser{})

New:

doc, err := openapi.Build("API", "1.0.0", &GetUser{})

OpenAPIMeta() is still supported.

Deprecation Message

Suggested README notice for go-module-router:

go-module-router is superseded by go-foundation.

HTTP routing, declarative handlers, DI, OpenAPI, actions, and relay support now live in go-foundation. Existing projects can keep using this module, but new projects should start from go-foundation.