Transform your Dart data classes into JSON Schema, OpenAPI, and Protocol Buffers specifications with a single annotation.
@Spectra()
@freezed
class User with _$User {
const factory User({
@Field(format: StringFormat.email) required String email,
@Field(minimum: 0, maximum: 150) int? age,
}) = _User;
}| Feature | Description |
|---|---|
| π― Multi-format | JSON Schema, OpenAPI 3.0/3.1, Protocol Buffers |
| π§ Freezed | Full support including union types |
| π¦ json_serializable | Seamless integration |
| β Constraints | String, number, array validation |
| π References | $ref, $defs, discriminated unions |
dart pub add spectra_schema
dart pub add dev:build_runnerimport 'package:freezed_annotation/freezed_annotation.dart';
import 'package:spectra_schema/spectra.dart';
part 'user.freezed.dart';
part 'user.g.dart';
@freezed
@Spectra(title: 'User')
class User with _$User {
const factory User({
@Field(minLength: 1, maxLength: 100) required String name,
@Field(format: StringFormat.email) required String email,
@Field(minimum: 0) int? age,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
@spectraOutput
static String get jsonSchema => _$UserJsonSchema;
}targets:
$default:
builders:
json_serializable:
options:
explicit_to_json: true
global_options:
freezed|freezed:
runs_before:
- spectra_schema|spectra_schemadart run build_runner buildprint(User.jsonSchema);
// {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
// "title": "User",
// "type": "object",
// "properties": {
// "name": { "type": "string", "minLength": 1, "maxLength": 100 },
// "email": { "type": "string", "format": "email" },
// "age": { "type": ["integer", "null"], "minimum": 0 }
// },
// "required": ["name", "email"]
// }@Spectra(
title: 'User',
description: 'A user object',
formats: {SpectraFormat.jsonSchema, SpectraFormat.openApi},
additionalProperties: false,
)// String
@Field(minLength: 1, maxLength: 100, pattern: r'^\w+$', format: StringFormat.email)
// Number
@Field(minimum: 0, maximum: 100, exclusiveMinimum: true, multipleOf: 0.5)
// Array
@Field(minItems: 1, maxItems: 10, uniqueItems: true)
// Meta
@Field(description: 'User email', deprecated: true, examples: ['a@b.com'])@Ignore()
String internalField;@freezed
@Spectra()
sealed class Result with _$Result {
const factory Result.success({required String data}) = Success;
const factory Result.error({required String message}) = Error;
}Generates oneOf with discriminator:
{
"oneOf": [
{ "$ref": "#/$defs/Success" },
{ "$ref": "#/$defs/Error" }
],
"discriminator": { "propertyName": "runtimeType" }
}@Spectra(formats: {SpectraFormat.jsonSchema})@Spectra(formats: {SpectraFormat.openApi})@Spectra(formats: {SpectraFormat.protobuf})syntax = "proto3";
message User {
string name = 1;
string email = 2;
optional int64 age = 3;
}| Format | Example |
|---|---|
email |
user@example.com |
uri |
https://example.com |
uuid |
550e8400-e29b-41d4-a716-446655440000 |
dateTime |
2024-01-15T09:30:00Z |
date |
2024-01-15 |
time |
09:30:00 |
ipv4 |
192.168.1.1 |
ipv6 |
2001:db8::1 |
hostname |
example.com |
- import 'package:soti_schema/soti_schema.dart';
+ import 'package:spectra_schema/spectra.dart';
- @SotiSchema()
+ @Spectra()
- @jsonSchema
+ @spectraOutput
# build.yaml
- soti_schema|openApiBuilder
+ spectra_schema|spectra_schemaMIT