Skip to content

Add OpenAPI Generator compatible output mode for C# code generators #152

@clemensv

Description

@clemensv

Summary

Add an option to s2cs (JSON Structure to C#) and a2cs (Avro to C#) commands that generates C# models compatible with OpenAPI Generator's output style.

Motivation

When integrating Avrotize-generated models with OpenAPI Generator-produced API clients, there's a structural mismatch:

Aspect OpenAPI Generator Avrotize (current)
Property style Option<T> wrapper with dual accessors Simple auto-properties
Null tracking Explicit Option<T>.IsSet for not-set vs null Standard nullable types
JSON serialization Custom JsonConverter<T> with manual Read/Write Attribute-based ([JsonPropertyName])
Validation IValidatableObject interface None

This makes it difficult to use Avrotize as a drop-in replacement for OpenAPI Generator's model generation while still using OpenAPI Generator for API client scaffolding.

Proposed Solution

Add a new flag to both commands:

avrotize s2cs schema.struct.json --out ./models --openapi-generator-compat
avrotize a2cs schema.avsc --out ./models --openapi-generator-compat

When enabled, the generated C# classes would include:

  1. Option<T> wrapper pattern for optional properties with dual accessors:

    public Option<string?> BitlyUrlOption { get; private set; }
    public string? BitlyUrl { get => BitlyUrlOption; set => BitlyUrlOption = new(value); }
  2. Custom JSON converter per class for fine-grained serialization control

  3. IValidatableObject implementation (can be empty initially)

  4. Constructor accepting all properties as Option<T> parameters

Example Comparison

Current Avrotize output (284 lines for Gif.cs):

public partial class Gif
{
    [JsonPropertyName("bitly_url")]
    public string? BitlyUrl { get; set; }
    // ...
}

With --openapi-generator-compat (matching OpenAPI Generator's 815 lines):

public partial class Gif : IValidatableObject
{
    [JsonIgnore]
    public Option<string?> BitlyUrlOption { get; private set; }
    
    [JsonPropertyName("bitly_url")]
    public string? BitlyUrl { get => BitlyUrlOption; set => BitlyUrlOption = new(value); }
    // ...
}

public class GifJsonConverter : JsonConverter<Gif> { /* ... */ }

Benefits

  • Enables using Avrotize for model generation while using OpenAPI Generator for API client scaffolding
  • Preserves three-way null semantics (not-set vs explicitly-null vs value)
  • Provides seamless interoperability without runtime mapping overhead

Additional Context

This came from investigating how to integrate oas2s (OpenAPI to JSON Structure) output with OpenAPI Generator's C# client. See analysis in PR #151.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions