Schema Constraints
APIMatic SDKs carry the validation constraints defined in your OpenAPI schemas onto the generated models as declarative attributes. Numeric bounds, string lengths, patterns, array rules, object property counts, and string formats are all expressed directly on the model, giving you a single, contract-driven source of truth that you can use to validate data before sending a request or after receiving a response.
The attributes are declarative: the SDK decorates the models for you, and you decide when and where to run validation using standard .NET validation utilities. This keeps the models lightweight while letting you opt into as much or as little validation as your application needs.
Constraints in Your OpenAPI Definition
Constraints are the standard JSON Schema keywords you already use in your OpenAPI definition. For example:
components:
schemas:
User:
type: object
required:
- name
- age
- roles
properties:
name:
type: string
minLength: 3
maxLength: 50
pattern: "^[A-Za-z ]+$"
age:
type: integer
minimum: 18
maximum: 60
rating:
type: number
minimum: 0
maximum: 5
multipleOf: 0.1
roles:
type: array
minItems: 1
maxItems: 5
uniqueItems: true
items:
type: string
Constraint Attributes on Generated Models
Each constraint is mapped to a corresponding attribute on the generated model property. Constraints covered by the .NET Base Class Library use the standard System.ComponentModel.DataAnnotations attributes, while the remaining constraints use attributes provided by the SDK under its Core.Validation.Attributes namespace.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
public record User
{
[JsonPropertyName("name")]
[StringLength(50, MinimumLength = 3)]
[RegularExpression("^[A-Za-z ]+$")]
public required string Name { get; init; }
[JsonPropertyName("age")]
[Minimum(18)]
[Maximum(60)]
public required int Age { get; init; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("rating")]
[Minimum(0.0)]
[Maximum(5.0)]
[MultipleOf(0.1)]
public double? Rating { get; init; }
[JsonPropertyName("roles")]
[MinLength(1)]
[MaxLength(5)]
[UniqueItems]
public required IReadOnlyList<string> Roles { get; init; }
}
The table below shows how each OpenAPI constraint maps to an attribute:
| OpenAPI Keyword | Attribute |
|---|---|
minLength / maxLength (string) | [MinLength] / [MaxLength], or the combined [StringLength] |
pattern | [RegularExpression] |
minItems / maxItems (array) | [MinLength] / [MaxLength] |
uniqueItems | [UniqueItems] |
minimum / maximum | [Minimum] / [Maximum] |
exclusiveMinimum / exclusiveMaximum | [ExclusiveMinimum] / [ExclusiveMaximum] |
multipleOf | [MultipleOf] |
minProperties / maxProperties (object) | [MinProperties] / [MaxProperties] |
format (email, hostname, json-pointer) | [Format(FormatKind.Email)] and related values |
The SDK-provided attributes live in the Core.Validation.Attributes namespace and behave like any other ValidationAttribute, so they integrate seamlessly with the standard .NET validation pipeline.
Validating Models
Because the attributes are declarative, validation runs whenever you choose to invoke it. Use System.ComponentModel.DataAnnotations.Validator to check an object against every constraint declared on its properties.
To validate a request before sending it:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
var user = new User
{
Name = "John Doe",
Age = 30,
Roles = new[] { "admin" },
};
var context = new ValidationContext(user);
var results = new List<ValidationResult>();
// validateAllProperties: true checks every decorated property.
bool isValid = Validator.TryValidateObject(user, context, results, validateAllProperties: true);
if (!isValid)
{
foreach (var result in results)
{
Console.WriteLine(result.ErrorMessage);
}
}
You can validate a response the same way after it has been deserialized:
var response = await client.GetUserAsync(userId);
var context = new ValidationContext(response);
var results = new List<ValidationResult>();
Validator.TryValidateObject(response, context, results, validateAllProperties: true);
If you prefer validation to throw on the first violation instead of collecting results, use Validator.ValidateObject, which raises a ValidationException when a constraint isn't met.
Schema constraint attributes are currently available in the C# v4 SDK (beta). Generated models carry the attributes automatically, and running validation is opt-in and fully under your control.
For union types whose members share a base type but differ by their constraints, see how the SDK selects the matching schema in oneOf and anyOf.