Schema Validation
Servus provides optional JSON Schema validation for service arguments and results. Validation is opt-in - services work fine without schemas.
How It Works
Define schemas using the schema DSL method (recommended) or as constants. The framework validates arguments before execution and results after execution. Invalid data raises ValidationError.
Preferred: Schema DSL Method
class ProcessPayment::Service < Servus::Base
schema(
arguments: {
type: "object",
required: ["user_id", "amount"],
properties: {
user_id: { type: "integer", example: 123 },
amount: { type: "number", minimum: 0.01, example: 100.0 }
}
},
result: {
type: "object",
required: ["transaction_id", "new_balance"],
properties: {
transaction_id: { type: "string", example: "txn_abc123" },
new_balance: { type: "number", example: 950.0 }
}
}
)
end
Pro tip: Add example or examples keywords to your schemas. These values can be automatically extracted in tests using servus_arguments_example() and servus_result_example() helpers. See the Testing documentation for details.
You can define just one schema if needed:
class SendEmail::Service < Servus::Base
schema arguments: {
type: "object",
required: ["email", "subject"],
properties: {
email: { type: "string", format: "email" },
subject: { type: "string" }
}
}
end
Alternative: Inline Constants
Constants are still supported for backwards compatibility:
class ProcessPayment::Service < Servus::Base
ARGUMENTS_SCHEMA = {
type: "object",
required: ["user_id", "amount"],
properties: {
user_id: { type: "integer" },
amount: { type: "number", minimum: 0.01 }
}
}.freeze
RESULT_SCHEMA = {
type: "object",
required: ["transaction_id", "new_balance"],
properties: {
transaction_id: { type: "string" },
new_balance: { type: "number" }
}
}.freeze
end
File-Based Schemas
For complex schemas, use JSON files instead of inline definitions. Create files at:
app/schemas/services/service_name/arguments.jsonapp/schemas/services/service_name/result.json
Schema Lookup Precedence
Servus checks for schemas in this order:
- schema DSL method (if defined)
- Inline constants (ARGUMENTS_SCHEMA, RESULT_SCHEMA)
- JSON files (in schema_root directory)
Schemas are cached after first load for performance.
Three Layers of Validation
Schema Validation (Servus): Type safety and structure at service boundaries
Business Rules (Service Logic): Domain-specific constraints during execution
Model Validation (ActiveRecord): Database constraints before persistence
Each layer has a different purpose - don't duplicate validation across layers.
Configuration
Change the schema file location if needed:
# config/initializers/servus.rb
Servus.configure do |config|
config.schema_root = Rails.root.join('config/schemas')
end
Clear the schema cache during development when schemas change:
Servus::Support::Validator.clear_cache!