diff --git a/core/deploy/loader/builder.go b/core/deploy/loader/builder.go index 1e2598ac..0b597bbd 100644 --- a/core/deploy/loader/builder.go +++ b/core/deploy/loader/builder.go @@ -11,6 +11,7 @@ import ( "github.com/primadi/lokstra/core/deploy" "github.com/primadi/lokstra/core/deploy/schema" "github.com/primadi/lokstra/core/router" + "github.com/primadi/lokstra/serviceapi" ) // Case-insensitive map lookup helpers @@ -881,22 +882,15 @@ func setupNamedDbPools(registry *deploy.GlobalRegistry, config *schema.DeployCon return nil } - // Type assert to interface with required methods - type DbPoolManager interface { - SetNamedDsn(name, dsn, schema string) - GetNamedPool(name string) (any, error) + dpm, ok := deploy.Global().GetServiceAny("dbpool-manager") + if !ok || dpm == nil { + return fmt.Errorf("dbpool-manager service not found in registry") } - - poolManager, ok := registry.GetServiceAny("dbpool-manager") - if !ok || poolManager == nil { - log.Println("Warning: named-db-pools defined but dbpool-manager service not registered") - return nil - } - - dbPoolManager, ok := poolManager.(DbPoolManager) + dbPoolManager, ok := dpm.(serviceapi.DbPoolManager) if !ok { - return fmt.Errorf("dbpool-manager does not implement required interface (SetNamedDsn, GetNamedPool)") + return fmt.Errorf("dbpool-manager service does not implement serviceapi.DbPoolManager interface") } + // Setup each pool for poolName, poolConfig := range config.NamedDbPools { // Extract DSN or build from components diff --git a/core/deploy/schema/temp.txt b/core/deploy/schema/temp.txt new file mode 100644 index 00000000..66edf7c0 --- /dev/null +++ b/core/deploy/schema/temp.txt @@ -0,0 +1,844 @@ +"external-service-definitions": { + "type": "object", + "description": "External service definitions (services outside this deployment). For external services, you typically need to override everything since their API structure may differ from internal conventions.", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "description": "Base URL of external service (supports resolver: ${VAR:default} or direct URL)", + "oneOf": [ + { "pattern": "^https?://" }, + { "pattern": "^\\$\\{.*\\}$" } + ] + }, + "type": { + "type": "string", + "description": "Factory type (optional) - Auto-creates service wrapper. Required if external service will be used in published-services for auto-router generation. Not needed if only accessed via GetRemoteService.", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "config": { + "type": "object", + "description": "Additional configuration for the factory (optional)", + "additionalProperties": true + }, + "router": { + "type": "object", + "description": "Router configuration for this external service. For external services, you typically need to override everything since their API structure may differ from internal conventions.", + "properties": { + "convention": { + "type": "string", + "description": "Convention type (rest, rpc, graphql) - Override of RegisterServiceType metadata", + "pattern": "^[a-z][a-z-]*$" + }, + "resource": { + "type": "string", + "description": "Resource name (singular) - Override of RegisterServiceType metadata", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "description": "Plural form of resource name - Override", + "pattern": "^[a-z][a-z-]*$" + }, + "path-prefix": { + "type": "string", + "description": "Path prefix for all routes (e.g., '/api/v1')" + }, + "path-rewrites": { + "type": "object", + "description": "Path rewrites for specific methods (method_name: new_path)", + "additionalProperties": { + "type": "string" + } + }, + "middlewares": { + "type": "array", + "description": "Router-level middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "hidden": { + "type": "array", + "description": "Method names to hide from router", + "items": { + "type": "string", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + } + }, + "custom": { + "type": "array", + "description": "Custom route definitions", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Method name", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + }, + "method": { + "type": "string", + "description": "HTTP method override (GET, POST, PUT, DELETE, PATCH)", + "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"] + }, + "path": { + "type": "string", + "description": "Path override (e.g., '/custom/{id}')" + }, + "middlewares": { + "type": "array", + "description": "Route-specific middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + } + } + }, + "additionalProperties": false + } + } + } + } + }, + "additionalProperties": false + } + } + }, + "deployments": { + "type": "object", + "description": "Deployment configurations", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "properties": { + "config-overrides": { + "type": "object", + "description": "Configuration overrides for this deployment", + "additionalProperties": true + }, + "middleware-definitions": { + "type": "object", + "description": "Deployment-level middleware definitions (will be normalized to {deployment}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "type": "string", + "description": "Middleware factory type identifier", + "pattern": "^[a-z][a-z0-9_-]*$" + }, + "config": { + "type": "object", + "description": "Middleware-specific configuration", + "additionalProperties": true + } + }, + "additionalProperties": false + } + } + }, + "service-definitions": { + "type": "object", + "description": "Deployment-level service definitions (will be normalized to {deployment}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "type": "string", + "description": "Service factory type identifier", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "depends-on": { + "type": "array", + "description": "List of service dependencies", + "items": { + "type": "string", + "description": "Dependency in format 'paramName:serviceName' or just 'serviceName'", + "pattern": "^([a-zA-Z][a-zA-Z0-9]*:)?[a-z][a-z0-9-]*$" + } + }, + "middlewares": { + "type": "array", + "description": "DEPRECATED: Use router.middlewares instead", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "router": { + "type": "object", + "description": "Embedded router definition for this service", + "properties": { + "convention": { + "type": "string", + "description": "Convention type (rest, rpc, graphql)", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "resource": { + "type": "string", + "description": "Singular form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "description": "Plural form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "path-prefix": { + "type": "string", + "description": "Path prefix for all routes" + }, + "path-rewrites": { + "type": "array", + "description": "Regex-based path rewrites", + "items": { + "type": "object", + "required": ["pattern", "replacement"], + "properties": { + "pattern": { + "type": "string" + }, + "replacement": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "middlewares": { + "type": "array", + "description": "Router-level middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "hidden": { + "type": "array", + "description": "Methods to hide from router", + "items": { + "type": "string" + } + }, + "custom": { + "type": "array", + "description": "Custom route definitions", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string" + }, + "method": { + "type": "string", + "pattern": "^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)$" + }, + "path": { + "type": "string" + }, + "middlewares": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + "config": { + "type": "object", + "description": "Service-specific configuration", + "additionalProperties": true + } + }, + "additionalProperties": false + } + } + }, + "router-definitions": { + "type": "object", + "description": "Deployment-level router definitions (will be normalized to {deployment}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "properties": { + "convention": { + "type": "string", + "description": "Convention type (rest, rpc, graphql)", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "resource": { + "type": "string", + "description": "Singular form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "description": "Plural form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "path-prefix": { + "type": "string", + "description": "Path prefix for all routes" + }, + "path-rewrites": { + "type": "array", + "description": "Regex-based path rewrites", + "items": { + "type": "object", + "required": ["pattern", "replacement"], + "properties": { + "pattern": { + "type": "string", + "description": "Regex pattern to match" + }, + "replacement": { + "type": "string", + "description": "Replacement string" + } + }, + "additionalProperties": false + } + }, + "middlewares": { + "type": "array", + "description": "Router-level middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "hidden": { + "type": "array", + "description": "Method names to hide from router", + "items": { + "type": "string", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + } + }, + "custom": { + "type": "array", + "description": "Custom route definitions", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Method name", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + }, + "method": { + "type": "string", + "description": "HTTP method override", + "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"] + }, + "path": { + "type": "string", + "description": "Path override" + }, + "middlewares": { + "type": "array", + "description": "Route-specific middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + } + }, + "external-service-definitions": { + "type": "object", + "description": "Deployment-level external service definitions (will be normalized to {deployment}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "description": "Base URL of external service", + "oneOf": [ + { "pattern": "^https?://" }, + { "pattern": "^\\$\\{.*\\}$" } + ] + }, + "type": { + "type": "string", + "description": "Factory type (optional)", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "config": { + "type": "object", + "description": "Additional configuration", + "additionalProperties": true + }, + "router": { + "type": "object", + "description": "Router configuration for this external service", + "properties": { + "convention": { + "type": "string", + "description": "Convention type", + "pattern": "^[a-z][a-z-]*$" + }, + "resource": { + "type": "string", + "description": "Resource name (singular)", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "description": "Plural form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "path-prefix": { + "type": "string", + "description": "Path prefix for all routes" + }, + "path-rewrites": { + "type": "object", + "description": "Path rewrites for specific methods", + "additionalProperties": { + "type": "string" + } + }, + "middlewares": { + "type": "array", + "description": "Router-level middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "hidden": { + "type": "array", + "description": "Method names to hide from router", + "items": { + "type": "string", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + } + }, + "custom": { + "type": "array", + "description": "Custom route definitions", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Method name", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + }, + "method": { + "type": "string", + "description": "HTTP method override", + "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"] + }, + "path": { + "type": "string", + "description": "Path override" + }, + "middlewares": { + "type": "array", + "description": "Route-specific middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + } + }, + "additionalProperties": false + } + } + } + } + }, + "additionalProperties": false + } + } + }, + "servers": { + "type": "object", + "description": "Server definitions", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["base-url"], + "properties": { + "base-url": { + "type": "string", + "description": "Server base URL (supports resolver: ${VAR:default} or direct URL)", + "oneOf": [ + { "pattern": "^https?://" }, + { "pattern": "^\\$\\{[^}]+\\}$" } + ] + }, + "middleware-definitions": { + "type": "object", + "description": "Server-level middleware definitions (will be normalized to {deployment}.{server}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "type": "string", + "description": "Middleware factory type identifier", + "pattern": "^[a-z][a-z0-9_-]*$" + }, + "config": { + "type": "object", + "description": "Middleware-specific configuration", + "additionalProperties": true + } + }, + "additionalProperties": false + } + } + }, + "service-definitions": { + "type": "object", + "description": "Server-level service definitions (will be normalized to {deployment}.{server}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "type": "string", + "description": "Service factory type identifier", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "depends-on": { + "type": "array", + "description": "List of service dependencies", + "items": { + "type": "string", + "description": "Dependency in format 'paramName:serviceName' or just 'serviceName'", + "pattern": "^([a-zA-Z][a-zA-Z0-9]*:)?[a-z][a-z0-9.-]*$" + } + }, + "middlewares": { + "type": "array", + "description": "DEPRECATED: Use router.middlewares instead", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9.-]*$" + } + }, + "router": { + "type": "object", + "description": "Embedded router definition for this service", + "properties": { + "convention": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "resource": { + "type": "string", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "pattern": "^[a-z][a-z-]*$" + }, + "path-prefix": { + "type": "string" + }, + "path-rewrites": { + "type": "array", + "items": { + "type": "object", + "required": ["pattern", "replacement"], + "properties": { + "pattern": { "type": "string" }, + "replacement": { "type": "string" } + }, + "additionalProperties": false + } + }, + "middlewares": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9.-]*$" + } + }, + "hidden": { + "type": "array", + "items": { "type": "string" } + }, + "custom": { + "type": "array", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { "type": "string" }, + "method": { + "type": "string", + "pattern": "^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)$" + }, + "path": { "type": "string" }, + "middlewares": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9.-]*$" + } + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + "config": { + "type": "object", + "description": "Service-specific configuration", + "additionalProperties": true + } + }, + "additionalProperties": false + } + } + }, + "router-definitions": { + "type": "object", + "description": "Server-level router definitions (will be normalized to {deployment}.{server}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "properties": { + "convention": { + "type": "string", + "description": "Convention type (rest, rpc, graphql)", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "resource": { + "type": "string", + "description": "Singular form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "description": "Plural form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "path-prefix": { + "type": "string", + "description": "Path prefix for all routes" + }, + "path-rewrites": { + "type": "array", + "description": "Regex-based path rewrites", + "items": { + "type": "object", + "required": ["pattern", "replacement"], + "properties": { + "pattern": { + "type": "string", + "description": "Regex pattern to match" + }, + "replacement": { + "type": "string", + "description": "Replacement string" + } + }, + "additionalProperties": false + } + }, + "middlewares": { + "type": "array", + "description": "Router-level middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9.-]*$" + } + }, + "hidden": { + "type": "array", + "description": "Method names to hide from router", + "items": { + "type": "string", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + } + }, + "custom": { + "type": "array", + "description": "Custom route definitions", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Method name", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + }, + "method": { + "type": "string", + "description": "HTTP method override", + "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"] + }, + "path": { + "type": "string", + "description": "Path override" + }, + "middlewares": { + "type": "array", + "description": "Route-specific middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9.-]*$" + } + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + } + }, + "external-service-definitions": { + "type": "object", + "description": "Server-level external service definitions (will be normalized to {deployment}.{server}.{name})", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "description": "Base URL of external service", + "oneOf": [ + { "pattern": "^https?://" }, + { "pattern": "^\\$\\{.*\\}$" } + ] + }, + "type": { + "type": "string", + "description": "Factory type (optional)", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "config": { + "type": "object", + "description": "Additional configuration", + "additionalProperties": true + }, + "router": { + "type": "object", + "description": "Router configuration for this external service", + "properties": { + "convention": { + "type": "string", + "description": "Convention type", + "pattern": "^[a-z][a-z-]*$" + }, + "resource": { + "type": "string", + "description": "Resource name (singular)", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "description": "Plural form of resource name", + "pattern": "^[a-z][a-z-]*$" + }, + "path-prefix": { + "type": "string", + "description": "Path prefix for all routes" + }, + "path-rewrites": { + "type": "object", + "description": "Path rewrites for specific methods", + "additionalProperties": { + "type": "string" + } + }, + "middlewares": { + "type": "array", + "description": "Router-level middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9.-]*$" + } + }, + "hidden": { + "type": "array", + "description": "Method names to hide from router", + "items": { + "type": "string", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + } + }, + "custom": { + "type": "array", + "description": "Custom route definitions", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Method name", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + }, + "method": { + "type": "string", + "description": "HTTP method override", + "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"] + }, + "path": { + "type": "string", + "description": "Path override" + }, + "middlewares": { + "type": "array", + "description": "Route-specific middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9.-]*$" + } + } + }, + "additionalProperties": false + } + } + } + } + }, + "additionalProperties": false + } + } + }, + "apps" diff --git a/docs/schema/lokstra.schema.json b/docs/schema/lokstra.schema.json new file mode 100644 index 00000000..55ca4696 --- /dev/null +++ b/docs/schema/lokstra.schema.json @@ -0,0 +1,317 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://lokstra.dev/schemas/deploy.json", + "title": "Lokstra Deployment Configuration", + "description": "Schema for Lokstra deployment configuration files", + "type": "object", + "properties": { + "configs": { + "type": "object", + "description": "Global configuration definitions", + "patternProperties": { + "^[A-Z][A-Z0-9_]*$": { + "description": "Configuration value (string, number, boolean, or object)", + "oneOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "boolean" }, + { "type": "object" }, + { "type": "array" } + ] + } + } + }, + "middleware-definitions": { + "type": "object", + "description": "Middleware definitions with types and configurations", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "type": "string", + "description": "Middleware factory type identifier", + "pattern": "^[a-z][a-z0-9_-]*$" + }, + "config": { + "type": "object", + "description": "Middleware-specific configuration", + "additionalProperties": true + } + }, + "additionalProperties": false + } + } + }, + "service-definitions": { + "type": "object", + "description": "Service definitions", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "type": "string", + "description": "Service factory type identifier", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "depends-on": { + "type": "array", + "description": "List of service dependencies", + "items": { + "type": "string", + "description": "Dependency in format 'paramName:serviceName' or just 'serviceName'", + "pattern": "^([a-zA-Z][a-zA-Z0-9]*:)?[a-z][a-z0-9-]*$" + } + }, + "config": { + "type": "object", + "description": "Service-specific configuration", + "additionalProperties": true + } + }, + "additionalProperties": false + } + } + }, + "router-definitions": { + "type": "object", + "description": "Router definitions (auto-generated from services)", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["service"], + "properties": { + "service": { + "type": "string", + "description": "Service name to create router from", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "overrides": { + "type": "string", + "description": "Reference to router-overrides definition name", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "additionalProperties": false + } + } + }, + "router-overrides": { + "type": "object", + "description": "Router override definitions", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "properties": { + "path-prefix": { + "type": "string", + "description": "Path prefix for all routes (e.g., '/api/v1')" + }, + "middlewares": { + "type": "array", + "description": "Router-level middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "hidden": { + "type": "array", + "description": "Method names to hide from router", + "items": { + "type": "string", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + } + }, + "custom": { + "type": "array", + "description": "Custom route definitions", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Method name", + "pattern": "^[A-Z][a-zA-Z0-9]*$" + }, + "method": { + "type": "string", + "description": "HTTP method override (GET, POST, PUT, DELETE, PATCH)", + "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"] + }, + "path": { + "type": "string", + "description": "Path override (e.g., '/custom/{id}')" + }, + "middlewares": { + "type": "array", + "description": "Route-specific middleware names", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + } + }, + "external-service-definitions": { + "type": "object", + "description": "External service definitions (services outside this deployment). For external services, you typically need to override everything since their API structure may differ from internal conventions.", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "description": "Base URL of external service (supports resolver: ${VAR:default} or direct URL)", + "oneOf": [ + { "pattern": "^https?://" }, + { "pattern": "^\\$\\{.*\\}$" } + ] + }, + "type": { + "type": "string", + "description": "Factory type (optional) - Auto-creates service wrapper. Required if external service will be used in published-services for auto-router generation. Not needed if only accessed via GetRemoteService.", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "config": { + "type": "object", + "description": "Additional configuration for the factory (optional)", + "additionalProperties": true + }, + "resource": { + "type": "string", + "description": "Resource name (singular) - Override of RegisterServiceType metadata", + "pattern": "^[a-z][a-z-]*$" + }, + "resource-plural": { + "type": "string", + "description": "Plural form of resource name - Override", + "pattern": "^[a-z][a-z-]*$" + }, + "convention": { + "type": "string", + "description": "Convention type (rest, rpc, graphql) - Override of RegisterServiceType metadata", + "pattern": "^[a-z][a-z-]*$" + }, + "overrides": { + "type": "string", + "description": "Reference to router-overrides definition for full path customization", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "additionalProperties": false + } + } + }, + "deployments": { + "type": "object", + "description": "Deployment configurations", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "properties": { + "config-overrides": { + "type": "object", + "description": "Configuration overrides for this deployment", + "additionalProperties": true + }, + "servers": { + "type": "object", + "description": "Server definitions", + "patternProperties": { + "^[a-z][a-z0-9-]*$": { + "type": "object", + "required": ["base-url"], + "properties": { + "base-url": { + "type": "string", + "description": "Server base URL (supports resolver: ${VAR:default} or direct URL)", + "oneOf": [ + { "pattern": "^https?://" }, + { "pattern": "^\\$\\{[^}]+\\}$" } + ] + }, + "apps": { + "type": "array", + "description": "Applications on this server (optional if using shorthand fields)", + "items": { + "type": "object", + "required": ["addr"], + "properties": { + "addr": { + "type": "string", + "description": "Application address (supports resolver: ${VAR:default} or direct address like ':8080', '127.0.0.1:8080', 'unix:/tmp/app.sock')", + "oneOf": [ + { "pattern": "^(:[0-9]+|[0-9.]+:[0-9]+|unix:.+)$" }, + { "pattern": "^\\$\\{.*\\}$" } + ] + }, + "routers": { + "type": "array", + "description": "Routers to include in this app", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "published-services": { + "type": "array", + "description": "Services to auto-generate routers for", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + } + }, + "additionalProperties": false + } + }, + "addr": { + "type": "string", + "description": "Shorthand: Application address (supports resolver: ${VAR:default} or direct address)", + "oneOf": [ + { "pattern": "^(:[0-9]+|[0-9.]+:[0-9]+|unix:.+)$" }, + { "pattern": "^\\$\\{.*\\}$" } + ] + }, + "routers": { + "type": "array", + "description": "Shorthand: Routers for the shorthand app", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + }, + "published-services": { + "type": "array", + "description": "Shorthand: Services to auto-generate routers for in the shorthand app", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$" + } + } + }, + "additionalProperties": false + } + } + } + }, + "additionalProperties": false + } + } + } + }, + "additionalProperties": false +} diff --git a/serviceapi/dbpool.go b/serviceapi/dbpool.go index 9701f200..cad6a250 100644 --- a/serviceapi/dbpool.go +++ b/serviceapi/dbpool.go @@ -2,8 +2,6 @@ package serviceapi import ( "context" - - "github.com/primadi/lokstra/lokstra_registry" ) // DbPool defines a connection pool interface @@ -21,26 +19,26 @@ type DbPool interface { // This is useful for multi-tenant applications. AcquireMultiTenant(ctx context.Context, schema string, tenantID string) (DbConn, error) - lokstra_registry.Shutdownable + Shutdownable } type DbPoolWithSchema interface { Acquire(ctx context.Context) (DbConn, error) - lokstra_registry.Shutdownable + Shutdownable } type DbPoolWithTenant interface { Acquire(ctx context.Context) (DbConn, error) - lokstra_registry.Shutdownable + Shutdownable } type RowMap = map[string]any // DbConn represents a live DB connection (e.g. from pgxpool) type DbConn interface { - lokstra_registry.Shutdownable + Shutdownable Begin(ctx context.Context) (DbTx, error) Transaction(ctx context.Context, fn func(tx DbExecutor) error) error Ping(context context.Context) error diff --git a/serviceapi/dbpool_manager.go b/serviceapi/dbpool_manager.go index 5b628b13..d833204f 100644 --- a/serviceapi/dbpool_manager.go +++ b/serviceapi/dbpool_manager.go @@ -2,8 +2,6 @@ package serviceapi import ( "context" - - "github.com/primadi/lokstra/lokstra_registry" ) type DbPoolManager interface { @@ -40,5 +38,5 @@ type DbPoolManager interface { // acquire connection for the given name AcquireNamedConn(ctx context.Context, name string) (DbConn, error) - lokstra_registry.Shutdownable + Shutdownable } diff --git a/serviceapi/helper.go b/serviceapi/helper.go new file mode 100644 index 00000000..19513097 --- /dev/null +++ b/serviceapi/helper.go @@ -0,0 +1,5 @@ +package serviceapi + +type Shutdownable interface { + Shutdown() error +}