Skip to main content

Data Transfer Object (DTO)

Vaden uses the concept of DTOs (Data Transfer Objects) to safely transport data between client and server. DTOs are tightly integrated with the serialization system known as DSON, which handles converting objects to and from JSON.

@DTO() Annotation

To define a DTO in Vaden, annotate the class with @DTO(). This marks the class for code generation so that Vaden can handle:

  • Automatic fromJson and toJson conversion.
  • Input validation (via Validator mixin).
  • Schema generation for OpenAPI.
()
class Credentials with Validator<Credentials> {
final String username;
final String password;

Credentials(this.username, this.password);

static Credentials fromJson(Map<String, dynamic> json) {
return Credentials(json['username'], json['password']);
}


LucidValidator<Credentials> validate(ValidatorBuilder<Credentials> builder) {
return builder
.ruleFor((c) => c.username, key: 'username').notEmpty()
.ruleFor((c) => c.password, key: 'password').minLength(6);
}
}

Additionally, you can return a DTO directly from a controller method instead of a Response. Vaden will automatically serialize it to JSON:

('/me')
UserProfile getProfile() => UserProfile('Alice');

This makes the controller cleaner while still returning a proper application/json response.

Json Key

If you want to use a different key in the JSON than the field name, you can use the @JsonKey() annotation:

()
class Credentials with Validator<Credentials> {
('user_name')
String username;

String password;

Credentials(this.username, this.password);

}

Complex Objects parse

DTOs can also contain other DTOs. Vaden will automatically handle the serialization and deserialization of nested objects, but you can also use @UseParse() to specify a custom parser for a field. This is useful for complex types or when you want to control the serialization format:

()
class BaseDto {
final String id;

(DateTimeParse)
final DateTime createdAt;

(DateTimeParse)
final DateTime? updatedAt;

BaseDto({
required this.id,
required this.createdAt,
required this.updatedAt,
});
}

class DateTimeParse extends ParamParse<DateTime?, String> {
const DateTimeParse();


String toJson(DateTime? param) {
return param?.toIso8601String() ?? '';
}


DateTime? fromJson(String? json) {
return DateTime.tryParse(json ?? '');
}
}

Deserialization with @Body()

When a controller method uses @Body(), Vaden will:

  • Read the request JSON body.
  • Look up the corresponding @DTO().
  • Deserialize the data using DSON.
  • Optionally validate the object before passing it to your method.
('/login')
String login(() Credentials credentials) {
return Response.ok(credentials.username);
}

Only @DTO() classes are allowed in @Body() parameters.

DSON

DSON is Vaden’s automatic serializer. It is responsible for:

  • Converting DTOs from JSON (fromJson<T>()).
  • Converting objects to JSON (toJson<T>()).
  • Generating OpenAPI schemas.

You can inject it anywhere:

()
class DebugService {
final DSON dson;
DebugController(this.dson);

String serializeCredentials( Map<String, dynamic> body) {
final dto = dson.fromJson<Credentials>(body);
return Response.ok(dson.toJson(dto));
}
}

Benefits

  • No need to write boilerplate serializers.
  • Clean error handling via validation.
  • Fully typed and OpenAPI-ready.

By using @DTO() and DSON together, Vaden ensures reliable and clean data exchange between client and server.