Skip to content

Commit e502c24

Browse files
intel352claude
andauthored
refactor: replace concrete type assertions with capability interfaces (closes #59) (#120)
Replace two concrete type assertions in cmd/server/main.go with interface checks: 1. svc.(*module.OpenAPIGenerator) → svc.(interfaces.SchemaRegistrar) - Define SchemaRegistrar in interfaces/ with Name(), RegisterAdminSchemas(), ApplySchemas() methods - Add RegisterAdminSchemas() method to *OpenAPIGenerator that delegates to the package-level RegisterAdminSchemas function - Add compile-time check: var _ interfaces.SchemaRegistrar = (*OpenAPIGenerator)(nil) 2. svc.(*module.WorkflowRegistry) → svc.(interfaces.WorkflowStoreProvider) - Define WorkflowStoreProvider in interfaces/ with Name() and WorkflowStore() any - Add WorkflowStore() any method to *WorkflowRegistry returning the store opaquely (avoids interfaces→module circular import) - Add compile-time check: var _ interfaces.WorkflowStoreProvider = (*WorkflowRegistry)(nil) No behaviour is changed; only the mechanism for identifying capable services is updated. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 23d7164 commit e502c24

4 files changed

Lines changed: 66 additions & 6 deletions

File tree

cmd/server/main.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/GoCodeAlone/workflow/dynamic"
3030
"github.com/GoCodeAlone/workflow/environment"
3131
"github.com/GoCodeAlone/workflow/handlers"
32+
"github.com/GoCodeAlone/workflow/interfaces"
3233
"github.com/GoCodeAlone/workflow/module"
3334
"github.com/GoCodeAlone/workflow/observability"
3435
"github.com/GoCodeAlone/workflow/observability/tracing"
@@ -479,8 +480,8 @@ func registerManagementServices(logger *slog.Logger, app *serverApp) {
479480

480481
// Enrich OpenAPI spec via the service registry
481482
for _, svc := range engine.GetApp().SvcRegistry() {
482-
if gen, ok := svc.(*module.OpenAPIGenerator); ok {
483-
module.RegisterAdminSchemas(gen)
483+
if gen, ok := svc.(interfaces.SchemaRegistrar); ok {
484+
gen.RegisterAdminSchemas()
484485
gen.ApplySchemas()
485486
logger.Info("Registered typed OpenAPI schemas", "module", gen.Name())
486487
}
@@ -506,10 +507,12 @@ func (app *serverApp) initStores(logger *slog.Logger) error {
506507
// Discover the WorkflowRegistry from the service registry
507508
var store *module.V1Store
508509
for _, svc := range engine.GetApp().SvcRegistry() {
509-
if reg, ok := svc.(*module.WorkflowRegistry); ok {
510-
store = reg.Store()
511-
logger.Info("Using WorkflowRegistry store", "module", reg.Name())
512-
break
510+
if provider, ok := svc.(interfaces.WorkflowStoreProvider); ok {
511+
if s, ok := provider.WorkflowStore().(*module.V1Store); ok {
512+
store = s
513+
logger.Info("Using WorkflowRegistry store", "module", provider.Name())
514+
break
515+
}
513516
}
514517
}
515518

interfaces/registry.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package interfaces
2+
3+
// SchemaRegistrar is implemented by any service that can register admin
4+
// schemas into an OpenAPI specification and apply them. Using this interface
5+
// in cmd/server allows the server to enrich the OpenAPI spec without holding
6+
// a concrete *module.OpenAPIGenerator pointer.
7+
//
8+
// *module.OpenAPIGenerator satisfies this interface.
9+
type SchemaRegistrar interface {
10+
// Name returns the module name (used for logging).
11+
Name() string
12+
13+
// RegisterAdminSchemas registers all admin API request/response schemas
14+
// onto this generator. Equivalent to calling module.RegisterAdminSchemas(gen).
15+
RegisterAdminSchemas()
16+
17+
// ApplySchemas applies all previously registered component schemas and
18+
// operation schema overrides to the current OpenAPI spec.
19+
ApplySchemas()
20+
}
21+
22+
// WorkflowStoreProvider is implemented by any service that exposes a workflow
23+
// data store. Using this interface in cmd/server decouples the server startup
24+
// code from the concrete *module.WorkflowRegistry type.
25+
//
26+
// *module.WorkflowRegistry satisfies this interface.
27+
type WorkflowStoreProvider interface {
28+
// Name returns the module name (used for logging).
29+
Name() string
30+
31+
// WorkflowStore returns the underlying workflow data store as an opaque
32+
// value. The caller is responsible for asserting the concrete type
33+
// (typically *module.V1Store) when further operations are required.
34+
WorkflowStore() any
35+
}

module/openapi_generator.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ import (
1010
"sync"
1111

1212
"github.com/CrisisTextLine/modular"
13+
"github.com/GoCodeAlone/workflow/interfaces"
1314
"gopkg.in/yaml.v3"
1415
)
1516

17+
// Compile-time assertion: *OpenAPIGenerator must satisfy interfaces.SchemaRegistrar.
18+
var _ interfaces.SchemaRegistrar = (*OpenAPIGenerator)(nil)
19+
1620
// --- OpenAPI 3.0 spec structs (minimal inline definitions) ---
1721

1822
// OpenAPISpec represents a minimal OpenAPI 3.0 specification document.
@@ -681,3 +685,10 @@ func (g *OpenAPIGenerator) ApplySchemas() {
681685
}
682686
}
683687
}
688+
689+
// RegisterAdminSchemas satisfies the interfaces.SchemaRegistrar interface.
690+
// It delegates to the package-level RegisterAdminSchemas function, registering
691+
// all admin API request/response schemas onto this generator.
692+
func (g *OpenAPIGenerator) RegisterAdminSchemas() {
693+
RegisterAdminSchemas(g)
694+
}

module/workflow_registry.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ import (
55
"fmt"
66

77
"github.com/CrisisTextLine/modular"
8+
"github.com/GoCodeAlone/workflow/interfaces"
89
)
910

11+
// Compile-time assertion: *WorkflowRegistry must satisfy interfaces.WorkflowStoreProvider.
12+
var _ interfaces.WorkflowStoreProvider = (*WorkflowRegistry)(nil)
13+
1014
// WorkflowRegistry is a module that provides the V1Store as a service,
1115
// making the workflow data store (companies, projects, workflows) available
1216
// to other modules via the service registry. It can either use a shared
@@ -84,6 +88,13 @@ func (w *WorkflowRegistry) Store() *V1Store {
8488
return w.store
8589
}
8690

91+
// WorkflowStore satisfies the interfaces.WorkflowStoreProvider interface.
92+
// It returns the underlying V1Store as an opaque any value so that the
93+
// interfaces package does not need to import the module package.
94+
func (w *WorkflowRegistry) WorkflowStore() any {
95+
return w.store
96+
}
97+
8798
func (w *WorkflowRegistry) ProvidesServices() []modular.ServiceProvider {
8899
return []modular.ServiceProvider{
89100
{Name: w.name, Description: "Workflow data registry (companies, projects, workflows)", Instance: w},

0 commit comments

Comments
 (0)