JSON Schema Integration
Ack schemas can be automatically converted into JSON Schema objects, allowing you to generate API documentation directly from your validation schemas.
Generating JSON Schemas
Use the toJsonSchema()
extension method available on any AckSchema
instance (requires importing package:ack/json_schema.dart
).
import 'package:ack/ack.dart';
import 'package:ack/json_schema.dart'; // Required for toJsonSchema() extension
import 'dart:convert';
// Example User Schema
final userSchema = Ack.object({
'id': Ack.int.positive().description('Unique user identifier'),
'name': Ack.string.minLength(2).maxLength(50).description('User\'s full name'),
'email': Ack.string.isEmail().description('User\'s email address'),
'role': Ack.string.isEnum(['admin', 'user', 'guest']).defaultValue('user'),
'isActive': Ack.boolean.defaultValue(true),
'tags': Ack.list(Ack.string).uniqueItems().description('List of user tags').nullable(),
'age': Ack.int.min(0).max(120).nullable().description('User\'s age'),
},
required: ['id', 'name', 'email'],
description: 'Represents a user in the system'
);
void main() {
// Convert the AckSchema to a JSON Schema Object Map
final jsonSchemaMap = userSchema.toJsonSchema();
// Pretty print the JSON representation of the JSON Schema
final jsonEncoder = JsonEncoder.withIndent(' ');
print(jsonEncoder.convert(jsonSchemaMap));
}
Output JSON (JSON Schema Object):
{
"type": "object",
"description": "Represents a user in the system",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": "Unique user identifier",
"minimum": 0,
"exclusiveMinimum": true
},
"name": {
"type": "string",
"description": "User\'s full name",
"minLength": 2,
"maxLength": 50
},
"email": {
"type": "string",
"format": "email",
"description": "User\'s email address"
},
"role": {
"type": "string",
"enum": [
"admin",
"user",
"guest"
],
"default": "user"
},
"isActive": {
"type": "boolean",
"default": true
},
"tags": {
"type": "array",
"description": "List of user tags",
"items": {
"type": "string"
},
"uniqueItems": true,
"nullable": true
},
"age": {
"type": "integer",
"format": "int64",
"description": "User\'s age",
"minimum": 0,
"maximum": 120,
"nullable": true
}
},
"required": [
"id",
"name",
"email"
]
}
How Constraints Map to JSON Schema
Ack attempts to map its built-in constraints to corresponding JSON Schema keywords:
Ack Constraint | JSON Schema Keyword | Notes |
---|---|---|
minLength(n) | minLength: n | String |
maxLength(n) | maxLength: n | String |
pattern(p) | pattern: p | String |
isEmail() | format: email | String |
isUrl() | format: url | String (Note: format is informational) |
isDate() | format: date | String |
isDateTime() | format: date-time | String |
isEnum([...]) | enum: [...] | String |
min(n) | minimum: n | Number (Int/Double) |
max(n) | maximum: n | Number (Int/Double) |
min(n, exclusive:true) | minimum: n , exclusiveMinimum: true | Number |
max(n, exclusive:true) | maximum: n , exclusiveMaximum: true | Number |
multipleOf(n) | multipleOf: n | Number (Int/Double) |
minItems(n) | minItems: n | List (Array) |
maxItems(n) | maxItems: n | List (Array) |
uniqueItems() | uniqueItems: true | List (Array) |
nullable() | nullable: true | Any Type |
defaultValue(v) | default: v | Any Type (Note: Use .defaultValue() on schema) |
description(d) | description: d | Any Type (Note: Use .description() on schema) |
Ack.int | type: integer , format: int64 | Type |
Ack.double | type: number , format: double | Type |
Ack.string | type: string | Type |
Ack.boolean | type: boolean | Type |
Ack.list(...) | type: array , items: {...} | Type |
Ack.object(...) | type: object , properties: {...} , required: [...] | Type |
Limitations:
- Custom Constraints:
SchemaConstraint
instances added via.constrain()
are not translated to JSON Schema as there's no standard way to represent arbitrary logic. - Complex Formats: Some specific formats (like UUID, achieved via
pattern
) don't have direct JSON Schemaformat
equivalents and are translated based on their base type (type: string
). You might add adescription
or use vendor extensions in your schema definition manually if needed. additionalProperties
: The translation ofadditionalProperties
might need review depending on the exact JSON Schema behavior desired (e.g.,additionalProperties: true
vsadditionalProperties: {}
vsadditionalProperties: <Schema>
).
Integrating into API Documentation
You can use the generated JSON Schema map within a larger API documentation structure.
// Assume you have a function to build the full API spec
Map<String, dynamic> buildApiSpecification() {
final userJsonSchema = userSchema.toJsonSchema();
return {
'schemas': {
'User': userJsonSchema
},
'endpoints': {
'/users': {
'post': {
'summary': 'Create a new user',
'requestBody': {
'required': true,
'content': {
'application/json': {
// Reference the generated schema
'schema': {
'\$ref': '#/schemas/User'
}
}
}
}
}
}
}
};
}
// Usage
final fullApiSpec = buildApiSpecification();
print(JsonEncoder.withIndent(' ').convert(fullApiSpec));
This allows you to maintain your validation logic and API documentation source in one place (your Ack schemas).