Schema Merging
Compose multiple service schemas into unified API documentation
The merger package composes schemas from multiple services into unified API documentation. This is essential for API gateways that present a single, federated API surface.
OpenAPI Merging
import "github.com/xraph/farp/merger"
m := merger.NewMerger(merger.DefaultMergerConfig())
result, err := m.Merge([]merger.ServiceSchema{
{Manifest: userManifest, Schema: userOpenAPI},
{Manifest: orderManifest, Schema: orderOpenAPI},
})
// result.Spec — merged OpenAPI 3.1.0 spec
// result.Conflicts — naming conflicts encountered
// result.Warnings — non-fatal issuesConfiguration
config := merger.MergerConfig{
DefaultConflictStrategy: farp.ConflictStrategyPrefix,
MergedTitle: "Federated API",
MergedDescription: "Unified API from all microservices",
MergedVersion: "1.0.0",
IncludeServiceTags: true,
SortOutput: true,
Servers: []merger.Server{
{URL: "https://api.example.com", Description: "Production"},
},
}Conflict Resolution
When multiple services define the same paths, components, or operation IDs, the merger applies a conflict strategy:
| Strategy | Behavior |
|---|---|
prefix (default) | Add service name prefix to conflicting items |
error | Return an error on any conflict |
skip | Keep the first occurrence, skip duplicates |
overwrite | Keep the last occurrence |
merge | Attempt to merge operations within the same path |
Per-Service Configuration
descriptor.Metadata = &farp.ProtocolMetadata{
OpenAPI: &farp.OpenAPIMetadata{
Composition: &farp.CompositionConfig{
IncludeInMerged: true,
ConflictStrategy: farp.ConflictStrategyPrefix,
ComponentPrefix: "UserSvc",
TagPrefix: "users",
OperationIDPrefix: "user",
},
},
}Conflict Types
| Type | Description |
|---|---|
path | Same path in multiple services |
component | Same component name |
tag | Same tag name |
operationId | Same operation ID |
securityScheme | Same security scheme name |
Route-Aware Merging
The merger respects each service's RoutingConfig. Paths are adjusted based on mount strategy before merging:
user-service (strategy: "service")
/users → /user-service/users
order-service (strategy: "versioned")
/orders → /order-service/v2/ordersComponent $ref references are updated automatically when prefixes are applied.
Multi-Protocol Merging
For services exposing multiple protocols, MultiProtocolMerger handles all schema types:
multiMerger := merger.NewMultiProtocolMerger(merger.DefaultMergerConfig())
result, err := multiMerger.MergeAll(manifests, func(hash string) (any, error) {
return schemaCache.Get(hash)
})
// result.OpenAPI — merged OpenAPI
// result.AsyncAPI — merged AsyncAPI
// result.GRPC — merged gRPC
// result.ORPC — merged oRPCGateway-Level Merging
The gateway client provides convenience methods:
// Merge all protocols for all services
result, err := gatewayClient.GenerateMergedSchemas(ctx, "")
// Merge for a specific service
result, err := gatewayClient.GenerateMergedSchemas(ctx, "user-service")
// Get merged OpenAPI as JSON
jsonData, err := gatewayClient.GetMergedOpenAPIJSON(ctx, "")How is this guide?