My aggregated monorepo of OCaml code, automaintained
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

OpenAPI Code Generator Roadmap#

This document outlines future enhancements for the OCaml OpenAPI code generator.

Recently Completed#

Union Type Generation (v0.2)#

  • Generate OCaml variant types for oneOf/anyOf schemas at the top level
  • Support discriminator-based codec (using Jsont.Object.Case)
  • Support try-each codec for schemas without discriminators
  • Currently handles schema-level unions; field-level unions fallback to Jsont.json

Typed Error Responses (v0.2)#

  • Enhanced api_error type with parsed_body field
  • error_body type: Raw, Json, or Typed variants
  • Generate error parsing code for operations with typed error schemas
  • Fallback to JSON/raw parsing for untyped errors

Field-Level Union Types (v0.3)#

  • Detect oneOf/anyOf in property definitions
  • For primitive-only unions (string|int|bool), generate polymorphic variants
  • For unions with schema references, fall back to Jsont.json due to module ordering constraints
  • Example: oneOf: [{type: string}, {type: integer}][ \String of string | `Int of int ]`

Runtime Validation (v0.3)#

  • Added validation functions: validated_string, validated_int, validated_float, validated_list
  • String validation: minLength, maxLength, pattern (using Re library with PCRE syntax)
  • Number validation: minimum, maximum, exclusiveMinimum, exclusiveMaximum
  • List validation: minItems, maxItems, uniqueItems
  • Validation errors reported via Jsont.Error.msgf
  • Added poly_union_decoder helper for polymorphic variant union types

Two-Phase Module Generation (v0.4)#

  • Solved the module ordering problem for union types referencing sibling schemas
  • Each prefix module now uses a two-phase structure:
    • Phase 1 (Types module): All type definitions, ordered by TYPE dependencies
    • Phase 2 (Full modules): Full modules with include Types.X + codecs, ordered by CODEC dependencies
  • Benefits:
    • Types can reference any sibling type (they're all in the same Types module)
    • Codecs can reference any sibling codec (properly ordered by codec dependencies)
    • Union type codecs can now use try-each decoding across multiple sibling schemas
  • Generated structure:
    module Prefix = struct
      module Types = struct
        module Schema_a = struct type t = { ... } end
        module Union_c = struct type t = A of Schema_a.t | B of Schema_b.t end
      end
      module Schema_a = struct include Types.Schema_a let jsont = ... end
      module Union_c = struct include Types.Union_c let jsont = (* uses Schema_a.jsont *) end
    end
    
  • Preserves the user-facing API: Prefix.Schema.t, Prefix.Schema.jsont, etc.

Planned Enhancements#

1. Streaming Support#

Priority: High

Add support for text/event-stream media type handling for Server-Sent Events.

Requirements:

  • Detect SSE endpoints in OpenAPI spec
  • Generate async iterator types for streaming responses
  • Requires requests library enhancement for chunked/streaming reads

Target API:

val stream_events :
  t -> unit ->
  (Event.t, Openapi.Runtime.api_error) Seq.t

2. File Upload Support#

Priority: High

Handle multipart/form-data with binary parts for file uploads.

Requirements:

  • Detect multipart endpoints in spec
  • Generate proper file upload functions accepting Eio.Flow.source
  • Requires requests library multipart encoding support

Target API:

val upload_file :
  filename:string ->
  content_type:string ->
  body:_ Eio.Flow.source ->
  t -> unit ->
  UploadResponse.t

3. Authentication Code Generation#

Priority: Medium

Generate auth header injection based on securitySchemes.

Supported schemes:

  • apiKey (header, query, cookie)
  • http (basic, bearer)
  • oauth2 flows (implicit, password, clientCredentials, authorizationCode)
  • openIdConnect

Target API:

module Auth : sig
  type t =
    | Api_key of string
    | Bearer of string
    | Basic of { username: string; password: string }
    | OAuth2 of { access_token: string; refresh_token: string option }

  val with_auth : t -> client -> client
end

4. Additional Schema Features#

Priority: Medium

4.1 additionalProperties#

Convert to OCaml string maps:

type t = { known_field: string; extra: Jsont.json StringMap.t }

4.2 const#

Generate literal type validation or unit variants.

4.3 default#

Handle default values for optional fields:

  • Make fields with defaults optional in constructors
  • Use the default value when field is absent during decoding
  • Consider generating builder-style constructors for complex schemas

4.4 readOnly/writeOnly#

Generate separate request/response types when fields differ.

5. Requests Library Enhancements#

Priority: Varies

These depend on enhancements to the requests library:

Feature Requests Support OpenAPI Use Case
Streaming responses Needed SSE, large downloads
Multipart form data Needed File uploads
Connection pooling Nice to have Performance
Retry with backoff Nice to have Resilience
WebSocket Future Real-time APIs

Architecture Notes#

Current Module Structure#

openapi
├── Spec        -- OpenAPI 3.x types
├── Codegen     -- Code generation
├── Runtime     -- Runtime utilities
└── Nestjs      -- NestJS error handling

Generated Code Structure#

generated_client
├── t           -- Client type
├── create      -- Constructor
└── Module1     -- Per-prefix modules
    ├── Schema1 -- Per-schema submodules
    │   ├── t
    │   ├── jsont
    │   └── accessors
    └── operation1  -- Operations

Design Principles#

  1. Type safety over flexibility: Prefer typed codecs over Jsont.json
  2. Minimal runtime: Keep Runtime module small
  3. Idiomatic OCaml: Use modules, not objects
  4. Eio-native: No blocking IO, cooperative concurrency
  5. Forward-compatible: Handle unknown fields gracefully

Contributing#

To add a new feature:

  1. Update openapi_spec.ml if new OpenAPI fields are needed
  2. Update openapi_codegen.ml with analysis and generation
  3. Update openapi_runtime.ml if new runtime support is needed
  4. Regenerate test specs: dune exec openapi-gen -- generate ...
  5. Verify with dune build @check and dune build @doc