Skip to content

API Genie CLI 0.9.0

Choose a tag to compare

@mykulyak mykulyak released this 10 Oct 18:52
· 3 commits to main since this release
e85d5e9

Highlights

  • Translations for all five standards. apigenie i18n extract and i18n apply work on OpenAPI, Swagger 2.0,
    AsyncAPI, Protobuf and GraphQL files: the texts are extracted keyed by JSON pointers, declaration names or schema
    coordinates, and translations are put back without touching the rest of the file
    (i18n).
  • Contract testing across OpenAPI, Swagger, AsyncAPI, gRPC and GraphQL, with TLS. apigenie test runs .http
    files (HTTP, gRPC, WebSocket, MQTT and GraphQL requests) and generated requests against a live API, and
    apigenie-mock --proxy-to sits between clients and a real server or broker (HTTP, WebSocket, MQTT, gRPC, GraphQL),
    checking every request and response against the contract. Both report coverage, JSON and JUnit reports, and fail
    CI with --fail-on and --min-coverage. TLS is supported throughout: the mock serves HTTPS, WSS and gRPC over TLS
    (--tls-cert, --tls-key), and requests and upstreams can be https://, wss:// and mqtts://, verified against
    the system's CA certificates (--ca-cert, --insecure) (test,
    mock server).
  • Code generation for five stacks. Clients and servers for TypeScript (fetch, Express, oRPC, WebSocket, Kafka on
    KafkaJS, Zod), Python (httpx, FastAPI, FastStream), Go (net/http, Kafka), Java (Spring clients and servers, Kafka)
    and C# (HttpClient, ASP.NET Core, Kafka), from OpenAPI 3.0–3.2 and, for event-driven APIs, AsyncAPI 3.x. Every target
    is checked by a conformance suite: snapshots, the target's own compiler and linter, and a run against
    apigenie-mock --proxy-to. The generators are a separate executable, apigenie-generator, installed with the CLI
    (apigenie-generator).
  • Web components for every spec type, and generate docs. The apg-* custom elements
    (@mykulyak/apigenie-web-components on npm) document OpenAPI, Swagger 2.0, AsyncAPI, Protobuf/gRPC and GraphQL
    APIs, with Try it out for HTTP and GraphQL, built on the same engine as the CLI compiled to WebAssembly.
    apigenie-generator docs compiles any of these files, several at once, into a docs bundle that the components
    render into a static site (npm install && npm run build), with translations, the git changelog and example
    files; it replaces generate doc html (see Upgrading).

Upgrading

  • apigenie generate is now apigenie-generator. The code generators moved out of apigenie into a separate
    executable, apigenie-generator, installed next to it by every archive and package, the npm package and Homebrew,
    and included in the mykulyak/apigenie Docker image (docker run --entrypoint apigenie-generator ...). Drop
    generate from the command line: apigenie generate client fetch spec.yaml -o out becomes
    apigenie-generator client fetch spec.yaml -o out. The options and the commands.generate section of the
    configuration file are unchanged; apigenie generate fails as an unknown command. The banners of generated files
    name the new command. The entries below still call the generators generate <target>. The design is ADR-123.
  • generate doc html is replaced by generate docs, with no alias. apigenie-generator docs openapi.yaml -o docs
    replaces apigenie generate doc html openapi.yaml --output docs; it takes several inputs of mixed families (OpenAPI,
    Swagger 2.0, AsyncAPI, GraphQL, Protobuf) and makes one site, and -c/--config, --i18n LOCALE=FILE,
    --package-name and --package-version keep their meaning. The output is no longer an Astro project but a docs
    bundle (apigenie-docs.json and documents/<id>/document.<locale>.json, ADR-122) with a package.json that
    depends on @mykulyak/apigenie-web-components instead of @mykulyak/api-genie-doc-html-template;
    npm install && npm run build still builds the static site, now into dist/, prerendered from the web components.
    --bundle-only writes the bundle alone, for a site built by other means. The CLI does not run Node. The
    configuration section commands.generate.doc_html is commands.generate.docs: html_title_prefix is title,
    i18n.default_locale and i18n.prefix_default_locale move to the top of the section (the locales come from
    --i18n), changelog keeps its name (also --changelog), and documents lists the inputs (file, id,
    title, proto_paths, examples). pages, operations, resources, search, sidebar, html_meta,
    template, openapi_schema, request_code_examples, use_request_body_examples, generate_response_schema,
    use_response_examples and fail_on_generator_error described the Astro layout and have no replacement: the site
    has the layout of <apg-api-reference> (navigation with search, one page per operation and schema), themed with
    the components' CSS custom properties and ::part(). Generated Astro projects keep building with the template they
    depend on, but nothing regenerates them: run generate docs into a new directory.
  • New dependency: Mbed TLS. apigenie and apigenie-mock link Mbed TLS 3.6 (Apache-2.0) for https://,
    wss:// and mqtts:// connections; release binaries grow by about 0.9 MB. Builds from source get it from vcpkg
    (mbedtls >= 3.6.2). Verifying servers needs the system's CA certificates: the Docker images now include them; in
    your own minimal images install ca-certificates. apigenie credits and apigenie license --library mbedtls list
    it.
  • Telemetry is opt-in. The CLI no longer writes .apigenie.telemetry in the current directory, and sends
    nothing. Set APIGENIE_TELEMETRY_FILE to a path to keep a local telemetry log; old .apigenie.telemetry files
    can be deleted.
  • i18n has subcommands. apigenie i18n FILE --output DEST becomes apigenie i18n extract FILE --output DEST.
  • lint fails on errors. lint exits with status 1 when issues of severity error remain (after --fix), so CI
    jobs that ran it only for its report fail now; lower the severities in the configuration to keep them passing.
  • apigenie-mock --stubs with a GraphQL schema or an AsyncAPI document exits with status 2 instead of ignoring
    the option.

Added

  • generate docs documents OpenAPI, Swagger 2.0, AsyncAPI, GraphQL and Protobuf files, several at once, as one static
    site: it writes a docs bundle (apigenie-docs.json; per document and locale the resolved document, or the
    documentation model of AsyncAPI, GraphQL and Protobuf files; with --changelog the git changelog, as apigenie changelog computes it; the example files next to a GraphQL schema and those listed in the configuration) and the
    npm project that renders it with @mykulyak/apigenie-web-components (npm install && npm run build): prerendered
    pages with declarative shadow DOM that hydrate in the browser, Try it out, a sitemap, a locale switcher for the
    --i18n locales, a changelog page and the examples. --bundle-only writes the bundle alone. Internal: the
    docs_bundle library (compileDocsBundle), changelog_helpers (the changelog of any family, shared with the
    changelog command), and graphql_describe and protobuf_describe, which write the documentation models that the
    graphql and protobuf WebAssembly modules used to write themselves, as asyncapi_describe does for AsyncAPI.
    The design is ADR-122.

  • generate server spring (OpenAPI) routes QUERY operations and additionalOperations such as COPY: their handlers
    carry @ExtensionMethod("QUERY"), which the generated ExtensionMethodConfiguration matches through a custom
    request condition of the request mapping (WebMvcRegistrations, or WebFluxRegistrations with reactive=true).
    pipeDelimited and spaceDelimited array query parameters are split on their separator (@DelimitedParameter),
    and query parameters with JSON content are read as JSON into their model (@JsonParameter), which is null and
    left unvalidated when the parameter is absent; both converters are registered by ParameterConversionConfiguration.
    Request media types whose bodies have different types get a handler each, named as the methods of
    generate client java (updateShipment for application/merge-patch+json, updateShipmentWithJsonPatch for the
    application/json-patch+json array). The new ApiExceptionHandler answers invalid requests with a 400 Problem
    (type, title, status, detail and, for constraint violations of the parameters, errors with the name,
    path and message of each), where a ConstraintViolationException used to answer 500. Conformance Level 3 of the
    target only expects the x-internal operation, which servers leave out, to fail.

  • generate server aspnet (OpenAPI) falls back to the default mapping of a discriminator (defaultMapping, or
    x-defaultMapping before 3.2): unions are read and written by the converters of generate client csharp, written
    next to the abstract record and attached with [JsonConverter] instead of [JsonPolymorphic], so a missing or
    unmapped discriminator reads as the default type, and the discriminator may be anywhere in the object on .NET 8 too.
    Request media types whose bodies have different types get an endpoint and API method each, named as the methods of
    the C# client (UpdateShipment for application/merge-patch+json, UpdateShipmentJsonPatch for the
    application/json-patch+json array) and restricted to their media types with Accepts<T>(), so routing picks the
    endpoint by Content-Type; the JSON Patch array used to be bound as a ShipmentPatch object (400). Conformance Level 3
    of the target passes with only the x-internal operation, which the server leaves out, expected to fail.

  • The codegen conformance runner decides that the x-internal operations of the fixture are expected to fail for servers
    that leave them out: omitsInternalOperations on a Level 3 entry of tests/conformance/targets.json (set for the
    ASP.NET and Spring servers) expects every request of those operations, the request set's and the generated one, to
    fail, instead of hand-written expected entries; a server that starts serving one still fails the level.

  • generate client kafkajs and generate server kafkajs generate TypeScript (Node.js) packages for the Kafka channels
    of AsyncAPI 3.x documents, on KafkaJS 2.2.4: the server for the described application (KafkaApp, taking a handler
    per received operation, with start() and stop()), the client for its counterpart (KafkaClient, with connect(),
    listen<Operation>(handler) and close()); perspective swaps either. Every sent operation gets a sender with a
    send<Message>(message) method per message, which validates the message, writes the constant headers (e.g.
    ce_type), the key and the topic, and, for an operation with a reply, sends the request with a new correlation id
    unless it has one and resolves with the typed reply, matched by correlation id on one reply consumer per operation
    (ReplyTimeoutError when none arrives in time). Received operations get handler interfaces with on<Message>(message, record) and onUnknown, dispatched by ce_type header, payload property or deduction; repliers return the reply,
    sent with the request's correlation id. Payloads are validated by dependency-free functions generated from the schemas
    (MessageValidationError), headers by their constraints. Avro payloads, topics with parameters and replies at
    runtime-expression addresses are skipped with a warning. Configured under commands.generate.client_kafkajs and
    commands.generate.server_kafkajs (layout, import_extension, perspective, validation); the design is ADR-120.
    The codegen conformance suite checks both commands in both perspectives at Levels 1 and 2 (tsc and ESLint) and, at
    Level 3, runs the client against the server on the Kafka service container both ways, as for Go and C#.

  • generate client ws and generate server ws generate the replies of operations whose reply is on the request's
    channel: the client gets typed on<Message> handlers for the reply messages and, when the messages have a correlation
    id in their payloads, request<Operation>(payload, { timeoutMs }) resolving with the reply carrying the request's id;
    the server session gets send<Message> methods for them and replyTo<Operation>(request, reply), which copies the
    request's correlation id into the reply. On the AsyncAPI conformance fixture, requestPickup() and
    replyToRequestPickup(). Replies on another channel or at a runtime-expression address are still reported as
    unsupported.

  • apigenie test sends WS regions to wss:// and MQTT regions to mqtts:// (or ssl://) URLs, with ports 443 and
    8883 by default. Their certificates are checked as for https://, with SNI and the URL's host name, so --ca-cert
    and --insecure apply. MQTT regions send their username and password settings in CONNECT (MQTT 3.1.1). A setting
    the region doesn't give comes from APIGENIE_MQTT_USERNAME and APIGENIE_MQTT_PASSWORD. A refusal names the reason
    (bad user name or password, not authorized). Credentials show as [redacted] in the console and the JSON and JUnit
    reports, as OAuth 2 secrets do, and a URL's user:password@ is shown as ***@. These URLs used to fail with "speaks plain WebSocket/MQTT only", and the
    credentials were noted as not sent. MQTT 5 is still not supported. The design is the amendment of ADR-110.

  • apigenie test with an AsyncAPI --spec checks HTTP requests against the document's HTTP channels, with the code
    and checks of the validating proxy: the channel and operation by path and method (a receive operation's HTTP
    binding's method, GET for a send one) or by # @operation, a receive operation's body, query and header fields
    against its messages and a 2XX response against its reply, a send operation's response against its messages. The
    requests count for their operations in the coverage, which used to show them as not tested, and --generate sends
    one request per HTTP channel operation (to --base-url, a ws:// URL taken as http://). A path of no HTTP
    channel is a note. Both apigenie test and apigenie-mock --proxy-to now check the query of an operation's HTTP
    binding (operation.query.invalid) and the header fields of a message's headers and HTTP binding headers, its
    traits' included (message.headers.invalid); responses other than 2XX are still not checked. The design is
    ADR-118, which amends ADR-110 and ADR-112.

  • apigenie test runs httpYac's OAuth 2 authorization instead of skipping it: Authorization: oauth2 [GRANT] [PREFIX] (and openid) with the client_credentials, password and refresh_token grants requests a token from
    <prefix>_tokenEndpoint (or the OpenID Connect discovery document of <prefix>_issuer) with the <prefix>_clientId,
    _clientSecret, _scope, _audience, _username, _password and _useAuthorizationHeader variables, keeps it
    for the run, requests it again (with its refresh token) when it expires, and sends Authorization: Bearer <token>.
    Token endpoints are reached like other requests, https:// included (--ca-cert, --insecure); a refused token
    request fails its request, which isn't sent. The authorization_code, implicit and device_code grants are still
    skipped, with a reason naming the grant. With --spec, requests sent with a token are checked by the new
    request.authorization.oauth2-scheme and request.authorization.oauth2-scope warnings (the operation has no OAuth 2
    scheme, the requested scopes aren't its). Tokens, client secrets, passwords and Authorization credentials show as
    [redacted] in the output, the reports and warnings. apigenie test import maps Postman's client credentials and
    password grants to these variables instead of disabling the requests. The design is ADR-117.

  • The asyncapi WebAssembly module (asyncapi.mjs, and asyncapi.web.mjs for browsers) exports
    describe(text, {fileName, files}). It returns the documentation model of an AsyncAPI 3.0 or 3.1 document as plain
    JSON ({"apigenieAsyncAPI": 1, …}):

    • servers, channels, operations and messages with their JSON pointers and source positions;
    • references followed and external files given in files bundled as apigenie asyncapi bundle does;
    • traits applied with JSON Merge Patch, and the defaults of the specification;
    • headers and payloads as schemas (other formats, such as Avro, kept with their schemaFormat), and a position
      table;
    • the problems found as issues.

    AsyncAPI 2.x is an error. It is built on the new asyncapi_describe library; the JSON Merge Patch of traits moved
    into the asyncapi library (asyncapi/traits.hpp), where the models generators use it too. ADR-119 has the design.

  • apigenie-mock, its validating proxy (--proxy-to) and apigenie test --spec take Swagger 2.0 documents: they
    convert them to OpenAPI 3.2 in memory, as convert --to openapi32 does, each time the document is read, and write
    no file. Locations stay those of the Swagger file: the lines of warnings, the lines and JSON pointers of
    x-apigenie-mock problems, and the new pointer of each operation in the contract reports. What the conversion
    can only approximate is told once at startup as info: lines with the Swagger file's line and JSON pointer
    ({"event":"info"} with apigenie test --formatter json). Swagger 2.0 documents used to be refused with exit
    status 3.

  • apigenie-mock --proxy-to mqtt://host:port (or mqtts://, verified like https:// upstreams) with an AsyncAPI
    document contract-tests a real MQTT broker: the mock's broker relays, each client getting a connection of its own to
    the broker with its identifier, version, clean start, keep-alive, will and credentials, and the broker's CONNACK and
    SUBACK. Every PUBLISH is checked against the topic's channel: what clients publish against its receive operations,
    with the QoS of their MQTT binding (message.qos.unexpected), what the broker delivers against its send operations
    (a channel without them: its receive operations and the replies sent there). In enforce mode invalid messages
    aren't forwarded (MQTT 5 clients get reason code 0x99). Wills, refusals and an unreachable broker (server
    unavailable) are passed on, clients stay connected across reloads, the log has mqtt-connect and mqtt-disconnect
    events, and coverage, --report, --report-junit, --fail-on and --min-coverage work as for WebSocket.
    --proxy-to can be repeated to proxy a WebSocket server and an MQTT broker at once (proxy.target takes a list).
    The design is ADR-112, which supersedes parts of ADR-097.

  • An AsyncAPI document's HTTP channels are proxied to the http(s):// or ws(s):// server of --proxy-to through
    the OpenAPI proxy's transport and checked against the AsyncAPI document: a receive operation's request body against
    its messages and a 2XX response's body against its reply, a send operation's response (GET) against its messages.
    In enforce mode invalid requests get 422 and invalid responses are replaced by 502; paths of no channel get 404 or
    405.

  • The AsyncAPI checks have channel.parameter.invalid: a value of an address parameter (a topic level, a path segment)
    outside the parameter's enum, for WebSocket, MQTT and HTTP channels.

  • mqtt::ClientConnection, an MQTT 3.1.1 and 5 client on the event loop (over TLS too), and broker hooks that decide
    CONNECT and SUBSCRIBE later and let the owner relay instead of delivering.

  • apigenie test runs GraphQL requests instead of skipping them: GRAPHQL URL requests of httpYac and the JetBrains
    HTTP client (the query, then its variables as JSON after a blank line; # @operation is the operationName) and
    POST requests whose body is a query are sent as GraphQL over HTTP, and JSON {"query": ...} bodies as they are.
    With a GraphQL schema as --spec (.graphql, .graphqls, .gql), each operation is validated against the schema
    before it is sent (an invalid one fails its request, not the run, and isn't sent), and each response is checked as
    apigenie-mock --proxy-to checks it: the shape of data and errors, value types, null in non-null fields that no
    error explains, __typename of abstract types and schema drift. Coverage is per field and per root field
    (--min-coverage is the share of fields), and --report and --report-junit are the GraphQL contract report of
    apigenie-mock with the run's tests and requests. --generate sends one request per field of Query and
    Mutation, with required arguments made up from their types as the mock makes up values; --base-url is the
    endpoint. --severity takes the GraphQL checks. The design is ADR-111; the GraphQL contract report moved from the
    apigenie-mock executable into the graphql_mock library, with the same output.

  • apigenie test runs httpYac's WS and MQTT requests and checks their messages against an AsyncAPI 3.x --spec.
    A region connects to a ws:// server or an mqtt:// broker (MQTT 3.1.1; topic, publish, subscribe, qos,
    retain headers), sends the messages of its body (separated by ===, === wait-for-server) and waits for the
    server's until # @expect N came or # @timeout (--message-timeout, 5000 ms) passed; the messages received are
    the response, a JSON array (?? body $[0].type == pickup.confirmed, ?? body $.length == 2, response.messages in
    scripts). The channel comes from the URL's path or the topic (# @channel names it); messages sent are checked
    against the channel's receive operations and messages received against its send operations, with the AsyncAPI
    proxy's checks. A message of a request/reply operation is paired with its reply, checked by the new contract checks
    message.reply.missing (warn) and message.reply.uncorrelated (error, a payload correlationId that differs);
    correlation ids and reply addresses in message headers are noted as not checkable over MQTT 3.1.1. Coverage per
    operation and message and the reports (--report, --report-junit, --formatter json, --min-coverage) are the
    AsyncAPI proxy's. --generate sends a region per WebSocket and MQTT channel with the receive operations' example
    messages, at --base-url ws://... and the new --mqtt-url. The design is ADR-110, extending ADR-092 and ADR-097.

  • apigenie-mock --proxy-to contract-tests a real gRPC server against its .proto file: the proxy checks the
    upstream's messages against their output types (also fields marked [(google.api.field_behavior) = REQUIRED],
    under proto3's presence rules, and deprecated fields and enum values), its status (HTTP status, content type,
    grpc-status, the percent-encoding of grpc-message, grpc-status-details-bin as a google.rpc.Status whose code
    is grpc-status), the number of messages of unary calls and the -bin metadata, with check ids such as
    response.message.incompatible and response.status.details-incompatible that contract.severity changes.
    Locations name the field (message[0]/items/2/sku). It counts the calls of each service and method, and writes the
    contract reports the OpenAPI, GraphQL and AsyncAPI proxies write (--report with "specification": "grpc",
    --report-junit with a test case per method, --fail-on, --min-coverage as the share of methods, exit status
    5, GET /__apigenie/contract). --strict (or grpc.validation.response: enforce) checks each upstream message
    before forwarding it and fails the call with INTERNAL. The upstream is HOST:PORT (cleartext HTTP/2) or
    https://host[:port] (HTTP/2 over TLS). The design is ADR-109.

  • apigenie test sends GRPC requests of .http files (httpYac's GRPC host:port/package.Service/Method with the
    request message as a proto3 JSON body, metadata as headers) with a .proto file as --spec, its imports looked up
    in the new --proto-path directories. Unary and server-streaming calls are made over HTTP/2, cleartext or over TLS
    for grpcs:// URLs (with --ca-cert and --insecure), and checked like the proxy's; a body that isn't a valid message fails the request with the field's path before it is sent.
    Assertions and scripts see the status code as status (?? status == 0), metadata and trailers as headers and the
    message as a JSON body (an array for server streaming). Client- and bidi-streaming requests are reported as skipped
    with a warning. --generate --base-url HOST:PORT (or grpcs://HOST:PORT) sends a request per method with a
    generated message. The
    reports are the gRPC contract report plus the requests (grpc, grpcStatus).

  • apigenie-mock --tls-cert FILE --tls-key FILE serves HTTPS, WSS and gRPC over TLS. Clients that ask for h2 by
    ALPN, such as browsers and gRPC clients, get HTTP/2. The settings are also tls.cert and tls.key in the
    configuration, and APIGENIE_MOCK_TLS_CERT and APIGENIE_MOCK_TLS_KEY. A separate admin port uses the same
    certificate, and the MQTT broker stays cleartext. The startup line shows https:// and wss:// URLs and
    "tls": true. TLS 1.2 and 1.3 come from Mbed TLS; the design is ADR-104.

  • apigenie-mock --proxy-to reaches TLS upstreams: https:// for the OpenAPI and GraphQL validating proxies,
    wss:// for the AsyncAPI WebSocket proxy, and https://host[:port] for gRPC (HTTP/2 over TLS with ALPN h2,
    shown as grpcs://). Certificates are verified against the system's roots: the macOS keychains, the Windows ROOT
    store, the Linux CA bundle, or SSL_CERT_FILE and SSL_CERT_DIR. --ca-cert FILE (repeatable; tls.ca_certs,
    APIGENIE_MOCK_CA_CERT) adds authorities, and --insecure (tls.insecure, APIGENIE_MOCK_INSECURE=1) skips
    verification. A rejected certificate gets the usual 502 with the reason.

  • apigenie test sends https:// requests, with the same --ca-cert FILE and --insecure options. Imported
    collections no longer need their HTTPS URLs pointed at a cleartext server.

  • generate server go also takes AsyncAPI 3.x documents and generates a Go module (Go 1.22) for their Kafka channels
    on franz-go (github.com/twmb/franz-go/pkg/kgo, pinned at v1.18.1, with a complete go.sum): structs, enums and
    sealed-interface unions with json tags and Validate methods for the payloads, a struct per message (key, typed
    headers, payload) validated before it is sent and after it is received, and an App with a consumer group and a
    handler interface per receive operation (several messages told apart by a constant payload property or header, e.g.
    the ce_type of binary-mode CloudEvents; others go to OnUnknown) and a typed sender per send operation. Request/reply
    operations with a reply channel return the reply from the sender, matched by its correlation id, and repliers send the
    handler's reply with the correlation id copied. Consumer groups and client ids come from the Kafka operation bindings.
    cmd/<package>/main.go takes the brokers from -brokers or KAFKA_BROKERS, wires stub handlers and stops cleanly on
    SIGINT and SIGTERM. Channels of other protocols are skipped with an info line, Avro payloads with a warning. Configured
    under commands.generate.server_go.asyncapi; the design is ADR-105. The codegen conformance suite checks both
    perspectives at Levels 1 and 2 and, at Level 3, has the application and the counterpart exchange the fixture's Kafka
    messages on the conformance workflow's new Kafka service container, including the requestLabelRender reply, an
    unknown ce_type and an invalid payload.

  • generate client go also takes AsyncAPI 3.x documents and generates a Go Kafka client package (a Go 1.22 module on
    franz-go v1.18.1, without main.go), by default for the counterpart of the described application and with
    perspective: application for the application itself. NewClient(options) creates the producer, Close() closes
    every client, and Options takes the brokers, a client id and franz-go options passed to every client. A send
    operation gets Send<Operation>(ctx, message), which writes the constant headers (e.g. ce_type), the key and the
    topic from the bindings; with several messages it takes an interface they implement. A request/reply operation gets
    a blocking Request<Operation>(ctx, message) that sets a fresh correlation id, waits for the reply until the
    context's deadline and returns it typed (an interface of the replies when there are several), with one reply
    consumer per operation shared by all requests. A receive operation gets Listen<Operation>(handler), consuming in the
    background with the server's dispatch, validation and repliers. Configured under
    commands.generate.client_go.asyncapi; the design is ADR-106. The codegen conformance suite checks both perspectives
    at Levels 1 and 2 and, at Level 3, runs the client against generate server go on the Kafka service container both
    ways: the server's events and label requests reach the client's listeners and replier, and the client's sends and
    requests (concurrent ones and one ending at its context's deadline included) reach the server's handlers.

  • Options.ClientID of the Go Kafka code of generate server go and generate client go replaces the producer's
    client id.

  • generate server aspnet also takes AsyncAPI 3.x documents and generates an ASP.NET Core project (.NET 8) for their
    Kafka channels on Confluent.Kafka 2.15.1, so a REST API and its events can live in one application: the payload models
    of generate client csharp (records, enums, unions read by converters of the System.Text.Json source-generated
    context), a record per message (key, typed headers with DataAnnotations, payload) validated before it is sent and
    after it is received, and per receive operation a handler interface, registered with dependency injection and resolved
    per record, and a consumer hosted as a BackgroundService in the operation's consumer group (several messages told
    apart by a constant payload property or header, e.g. the ce_type of binary-mode CloudEvents; others go to
    OnUnknownAsync). Records are committed once their handler returns and handled again when it throws; invalid
    records are logged and committed. Each send operation gets a typed sender; request/reply operations with a reply
    channel return the reply from Request<Message>Async, matched by correlation id, and repliers send the handler's
    reply with the correlation id copied. The AsyncApi:Kafka section of appsettings.json holds the brokers, topics,
    group and client ids (from the Kafka operation bindings) and further librdkafka properties, overridable by
    environment variables; stopping the host closes the consumers. Configured under
    commands.generate.server_aspnet.asyncapi; the design is ADR-107. The codegen conformance suite checks both
    perspectives at Levels 1 and 2 and, at Level 3, runs the application and the counterpart on the conformance
    workflow's Kafka service container, as for Go.

  • generate client csharp also takes AsyncAPI 3.x documents and generates a C# Kafka client library (.NET 8 class
    library on Confluent.Kafka 2.15.1), by default for the counterpart of the described application and with
    perspective: application for the application itself. <Name>KafkaClient has a producer per channel it sends to,
    whose Send<Message>Async writes the constant headers (e.g. ce_type), the key and the topic from the bindings; a
    request/reply operation gets Request<Message>Async, which sets a fresh correlation id, waits for the reply with a
    timeout (ReplyTimeout or an argument) and a CancellationToken, and returns it typed (an interface of the replies
    when there are several), with one reply consumer per client and a pending request per correlation id. Receive
    operations get the handler interfaces and hosted consumers of generate server aspnet, with its dispatch,
    validation and repliers. Add<Name>KafkaClient(configuration, configure) binds the options to the AsyncApi:Kafka
    section and registers the client and its producers, and its builder's Add<Operation>Handler<THandler>() registers
    a handler with its consumer. --package-name is the root namespace (default: the title followed by .Client), as
    for OpenAPI. Configured under commands.generate.client_csharp.asyncapi; the design is ADR-108. The codegen
    conformance suite checks both perspectives at Levels 1 and 2 and, at Level 3, runs the client against
    generate server aspnet on the Kafka service container both ways, including concurrent requests, a request timing
    out and a cancelled one.

  • generate client java also takes AsyncAPI 3.x documents and generates a Java Kafka client library (a Maven project
    for Java 21 on the Apache Kafka client 4.1.0, Jackson and Hibernate Validator, without Spring), by default for the
    counterpart of the described application and with perspective: application for the application itself. It shares
    the message records, models, dispatch, validation and repliers of generate server spring. <Name>KafkaClient
    (with <Name>KafkaClientOptions: servers, topics, client and group ids, reply timeout, producer and consumer
    properties) gets send<Message>(message) per send operation, writing the constant headers (e.g. ce_type), the key
    and the topic from the bindings; <operation>(message[, timeout]) per request/reply operation, which sets a fresh
    correlation id (header, payload pointer or kafka_correlationId) and completes with the typed reply, with one
    group-less reply consumer per client; and listen<Operation>(handler) per receive operation, consuming on a virtual
    thread with onUnknown and onError defaults. --library and -p are errors with AsyncAPI input. Configured under
    commands.generate.client_java.asyncapi; the design is ADR-121. The codegen conformance suite checks both
    perspectives at Levels 1 and 2 (mvn package, javac -Xlint:all -Werror) and, at Level 3, runs the client against
    generate server spring on the Kafka service container both ways, including concurrent requests and a timeout.

  • generate client python also takes AsyncAPI 3.x documents and generates an asyncio Kafka client package on aiokafka
    with the Pydantic models of generate server faststream, by default for the counterpart of the described application
    and with perspective: application for the application itself. messages.py has a dataclass per message (payload,
    headers, key) with headers models and their constant headers; <Name>KafkaClient, an async context manager, gets
    send_<message>(), request_<operation>(message, *, timeout=None) (fresh correlation id, typed reply, one
    group-less reply consumer per client, TimeoutError) and listen_<operation>(handler) with abstract handler classes
    (on_unknown and on_error defaults), by the Kafka rules of ADR-102. The package passes mypy --strict and ruff,
    and depends on aiokafka[lz4,snappy,zstd], so it reads topics other producers compress.
    Configured under commands.generate.client_python.asyncapi; the design is ADR-121. The codegen conformance suite
    checks both perspectives at Levels 1 and 2 and, at Level 3, runs the client's counterpart against the Kafka broker of
    generate server faststream's application and the client's application against its counterpart on the Kafka service
    container, including concurrent requests and a timeout.

  • generate server spring also takes AsyncAPI 3.x documents and generates a Spring Boot application (Maven project)
    for their Kafka channels: a record per payload and per message (key, payload, headers) with Jackson and Jakarta Bean
    Validation annotations, a @KafkaListener and a handler interface per receive operation (several messages told apart
    by a constant payload property or header, e.g. the ce_type of binary-mode CloudEvents), and a sender over
    KafkaTemplate per send operation. Request/reply operations with a reply channel use ReplyingKafkaTemplate, and
    replies carry the correlation id from the correlationId location. Topics, group and client ids (from the Kafka
    bindings) and servers go to application.yaml; message headers are merged with those of their traits as AsyncAPI
    does. Constraints Bean Validation can't express (draft-07 dependencies, if/then/else, tuples) become comments.
    Channels of other protocols are skipped with an info line, Avro payloads with a warning. Configured under
    commands.generate.server_spring.asyncapi; the design is ADR-102. The codegen conformance suite builds both
    perspectives at Level 2 and, at Level 3, has the application and the counterpart exchange the fixture's Kafka messages
    on an embedded broker (@EmbeddedKafka), including the requestLabelRender reply.

  • generate client go generates a Go client for the net/http package of Go 1.22 from an OpenAPI 3.x document, using
    the standard library only. One Client over a configurable *http.Client takes functional options (base URL,
    request editors, user agent, an option per security scheme such as WithAPIKey), and has a method per operation and
    request media type taking a context.Context first. Each method returns a response struct with one typed field per
    documented status and media type (JSON200, ApplicationProblemJSON404 *ProblemDetails) and the raw
    *http.Response; statuses of 400 and above also return an *APIError with the RFC 9457 problem details.
    text/event-stream and application/jsonl responses are iterators typed from itemSchema (x-itemSchema in 3.0
    and 3.1), binary responses stay open as io.ReadCloser, multipart bodies are structs whose binary parts (from
    contentMediaType or format: binary) are File values honouring encoding, content parameters are sent as
    JSON, operation and path servers are honoured (WithOperationServers(false) ignores them), credentials go to the
    operations that accept them, and x-internal operations are left out. Types and validation are shared with
    generate server go. Configured under commands.generate.client_go.

  • generate client csharp generates a C# client of an OpenAPI 3.0, 3.1 or 3.2 document for .NET 8 (or 9 and 10), built
    on HttpClient and System.Text.Json: a class library with one client per tag taking the HttpClient in its
    constructor (client.Shipments.ListShipmentsAsync()), a client of the whole API, and Add{Api}Client() registering
    them with IHttpClientFactory. Methods are async with a CancellationToken; they return the body of the success
    response, or a *Result by status when statuses have different bodies, and throw ApiException with the RFC 9457
    problem details of error responses. Every parameter style is supported, objects and content parameters (as JSON)
    included; bodies are JSON, text, binary, forms and multipart with FileParts for format: binary and
    contentMediaType fields; other media types of bodies and responses are methods of their own
    (UpdateShipmentJsonPatchAsync); server-sent events and JSON Lines are IAsyncEnumerable<T> typed by itemSchema
    (or x-itemSchema). Operation and path servers are honoured, x-internal operations left out, and bearer, basic,
    OAuth 2.0, OpenID Connect and API key credentials sent by DelegatingHandlers. The models are those of
    generate server aspnet, with a source-generated JsonSerializerContext and converters that read every oneOf/
    anyOf with a discriminator wherever the discriminator is, falling back to defaultMapping (or
    x-defaultMapping). The code builds with -warnaserror and the .NET analyzers. Configured under
    commands.generate.client_csharp.

  • The OpenAPI reader reads itemSchema of media types and defaultMapping of discriminators (OpenAPI 3.2), and the
    writer keeps them.

  • apigenie test import COLLECTION -o DIR imports Collection Format v2.0/v2.1 JSON exports into
    folder-based .http tests with environments, bearer/basic/API-key references, upload assets,
    inherited scripts and a marker-gated QuickJS pm compatibility subset. Status-only tests become
    ?? assertions; unsupported script blocks are preserved as comments with source-line warnings,
    and OAuth 2 requests are disabled. --spec adds operation bindings and saved-response example
    overlays without editing the spec. --environment can be repeated; --force opts into replacing
    generated files. Authentication secrets are stored only in the generated environment file.

  • apigenie test reads QUERY requests (the safe method with a body of OpenAPI 3.2) in .http files, and --spec
    takes OpenAPI 3.2 documents.

  • apigenie test runs the requests of .http files (the httpYac flavour, which the JetBrains HTTP client and VS Code's
    REST Client read too) against a live server and validates every request and response against an OpenAPI document
    (--spec) with the checks of apigenie-mock's validating proxy. Files have ### regions, {{var}} variables,
    @var = value definitions, # @name/# @ref/# @forceRef chaining with {{name.response.body.$.id}}
    references, {{ }} scripts and JetBrains > {% %} handlers (QuickJS: request, response, client, exports,
    test, assert, console), ?? assertions, and .env and http-client.env.json environments (--env,
    --env-file, --var). Requests are bound to operations by method and path; # @operation <operationId> picks
    one, # @operation off skips the checks. --generate sends one request per operation, from the document's
    examples or generated values. The run fails with exit status 5 when a request fails or when the contract gate
    (--fail-on, errors by default, and --min-coverage) does; --report and --report-junit write
    apigenie-mock's contract report with the requests added. Unknown directives are warnings. GraphQL, gRPC, HTTPS
    and OAuth 2 are not supported yet.

  • --strip-comments for format, overlay and lint --fix drops the comments of the files they write, which
    they keep otherwise (ADR-093): YAML comments of OpenAPI, Swagger and AsyncAPI documents, comments of Protobuf
    files and # comments of GraphQL documents, whose descriptions are kept.

  • i18n apply applies translations to Protobuf (.proto) and GraphQL (.graphql, .graphqls, .gql) files, keyed as
    i18n extract writes them: the leading comments of Protobuf declarations and the descriptions of GraphQL definitions
    are rewritten in place, in their style (// lines, /* */ blocks, block or quoted strings), and every other byte of
    the file is kept, comments included, so applying untranslated texts returns the file unchanged. Keys addressing no
    comment or description are warnings, or errors with --strict (ADR-103).

  • i18n extract extracts the texts of Swagger 2.0 documents, recognized by their swagger property, as it does for
    OpenAPI: titles, summaries and descriptions keyed by JSON pointers, which i18n apply puts back (ADR-103).

  • i18n apply --strip-comments drops the YAML comments of a spec or the # comments of a GraphQL file (descriptions are
    kept), as format, overlay and lint --fix do (ADR-093); it is refused for Protobuf files, whose translated texts
    are comments.

  • i18n apply applies translations to OpenAPI and AsyncAPI documents (JSON or YAML): each key of a translation file,
    a JSON pointer as i18n extract writes it, has the string it points to replaced by its value, and everything else
    is kept, YAML comments included. --translations can be repeated (later files override earlier ones), the result
    goes to --output or the standard output in the input format or that of --format, and keys pointing to nothing
    are warnings, or errors with --strict.

  • apigenie-mock --proxy-to ws://host:port with an AsyncAPI document is a validating proxy for contract testing of a
    WebSocket API: clients of a WebSocket channel are relayed to the real server (handshake headers and subprotocol
    passed on, 502 or 504 when it can't be reached), and every message of both sides is checked against the channel's
    receive (client messages) and send (server messages) operations. Violations carry checks such as
    message.incompatible and channel.send.undeclared, go to the log, and --strict keeps invalid messages from going
    on (the client gets an invalid-message or invalid-upstream-message problem instead). Coverage counts each message
    of each operation; --report, --report-junit, --fail-on, --min-coverage and GET /__apigenie/contract work as
    for OpenAPI. HTTP channels and the MQTT broker keep being mocked. contract.severity accepts the new checks.

  • apigenie-mock --proxy-to ... --record-dir DIR with an OpenAPI document writes each exchange the server answered as a
    stub file (getPet-1.yaml, or GET_health-1.yaml for a route of no operation: the request's method, path, query,
    headers and body, and the response's status, headers and body), which --stubs DIR (or stubs: in the
    configuration) replays without the server: before the document's examples, after Prefer and scenario rules, with
    X-Apigenie-Mock-Source: stub:getPet-1. --record-har FILE writes the whole session through the proxy, the mock's
    own answers included, as a HAR 1.2 file when the server stops, with comment (proxy or mock) and _apigenie
    (source, operation, upstream status, violations) on each entry. Both hide the values of Authorization, Cookie,
    Set-Cookie, Proxy-Authorization and X-Api-Key; proxy.redact sets the list. Also proxy.record_har and
    APIGENIE_MOCK_RECORD_HAR.

  • apigenie-mock --proxy-mode fallback with an OpenAPI document and --proxy-to: every request still goes to the
    real server, but when the server can't be reached, doesn't answer in time, or answers 404 or 501 for an operation of
    the document, the mock answers as it would without --proxy-to (examples, generated data, scenarios, Prefer).
    Such answers carry X-Apigenie-Mock-Upstream-Status, are logged with fallback: true and aren't
    response.status.unknown violations. The contract report tells the server's answers from the mock's:
    summary.sources, each operation's sources and mockedResponses, two JUnit properties and a Sources: line in
    the summary. Configured under proxy.mode.

  • apigenie-mock serves OpenAPI 3.2 documents: the query method and the methods of additionalOperations (such as
    COPY) are routed, validated and recorded in contract reports like the others. Streams described by itemSchema are
    answered with an empty body.

  • A codegen conformance suite runs every OpenAPI generator on one shared, realistic OpenAPI 3.2 fixture, the Carpet
    Express Shipping API (data/fixtures/openapi, with its 3.1 and 3.0 variants, Spring and mock overlays and a feature
    catalog). Level 1, part of every ctest run, compares each generator's output byte for byte with a checked-in snapshot
    and checks a per-target manifest of the features it doesn't support yet. Levels 2 and 3 type-check and lint the output
    with the target's own toolchain and run the generated code against the fixture's contract (clients behind
    apigenie-mock --proxy-to, servers with apigenie test --generate and a hand-written request set), for the fetch,
    C#, Go, Java and Python clients and the FastAPI, Spring, Go, ASP.NET and Express servers, and the zod schemas at Level
    2, in a Linux workflow that runs on generator changes and on demand. The results are in docs/codegen_conformance.md;
    the design is ADR-098.

  • The codegen conformance suite covers the AsyncAPI generators: generate client ws and generate server ws run on
    the Carpet Express Event Platform (data/fixtures/asyncapi), the AsyncAPI 3.0 event side of the same service (Kafka,
    WebSocket, MQTT 5, HTTP and AMQP channels, three request/reply styles, traits with a merge trap, bindings for all five
    protocols, draft-07 schemas), with a mock overlay and a feature catalog. Level 1 compares their output with
    snapshots and checks their manifests (the twelve non-WebSocket channels don't concern them; the reply of a
    request/reply operation is not generated yet). Level 2 type-checks and lints the generated packages; Level 3 drives
    the generated client and server through apigenie-mock as a validating WebSocket proxy. The matrix in
    docs/codegen_conformance.md has an AsyncAPI section; the design is ADR-100.

  • apigenie generate server faststream generates a Python FastStream application from the
    Kafka, AMQP (RabbitMQ) and MQTT channels of an AsyncAPI 3.x document: a broker per server (URL from an environment
    variable), a subscriber per receive operation (topics and patterns, consumer groups, queues, exchanges and routing
    keys, QoS from the bindings; several messages dispatched by a constant property) calling a handler you write in
    handlers.py, which regenerating keeps, and a publisher with a typed publish function per send operation. Payloads
    and headers become Pydantic v2 models, the same as generate client python's, with trait headers merged; headers
    are typed Header() parameters. Requests wait for their reply on the document's reply channel by correlation id;
    reply addresses in headers become reply_to arguments. WebSocket and HTTP channels and Avro payloads are skipped
    and reported. Configuration is commands.generate.server_faststream; it is in the codegen conformance suite at
    Levels 1 to 3. The design is ADR-101.

  • The codegen conformance suite runs generate server faststream at Level 3: the conformance workflow has RabbitMQ
    (with the fixture's virtual host) and Mosquitto service containers, pinned by digest, next to its Kafka one, and the
    generated application runs on the three brokers next to a counterpart. The counterpart publishes the fixture's
    examples (MQTT courier positions and sorter scans, AMQP customs decisions) to the application's handlers, receives
    what the application publishes (shipment events and label requests on Kafka, job offers on MQTT, customs filings on
    the customs exchange) and answers the label requests on their reply topic. The MQTT traffic goes through
    apigenie-mock's MQTT bridge, whose contract report checks it; the Kafka and AMQP messages and the MQTT 5 user
    properties are checked against the fixture in the harness (checkMessages(), ajv). Every item passes.

  • apigenie-mock --proxy-to http://host:port/graphql with a GraphQL schema is a validating proxy for contract
    testing: GraphQL requests are checked against the schema (graphql-js's rules, variables, deprecated usage) and
    forwarded to the real server, whose answers are checked field by field against the schema and the request's selection
    set (missing and unexpected fields, nulls no error explains, scalar, enum and __typename values, lists, the shape of
    errors, statuses and media types). The proxy also introspects the server and reports where its schema differs
    (schema.drift, schema.addition). Violations carry checks such as response.data.incompatible, go to the log and
    X-Apigenie-Mock-Violations-Detail, and --strict answers bad requests itself and replaces bad answers (502). Field
    and root field coverage, --report, --report-junit, --fail-on and --min-coverage work as for OpenAPI.
    --proxy-mode fallback lets examples, scenarios and scripts answer first, and --record-dir writes the server's
    answers as examples the mock replays.

  • generate server fastapi generates a Python FastAPI server from an OpenAPI 3.x document, with the project layout and
    options of openapi-generator's python-fastapi generator: pydantic 2 models (enums, unions with discriminators,
    recursive models, aliases and constraints), a router and a base class to implement per tag, security dependencies for
    API keys, HTTP, OAuth2 and OpenID Connect schemes with alternatives and scopes, pyproject.toml, a Dockerfile and
    pytest tests. Routes declare their status codes and response classes, parameters and bodies of every kind (forms,
    uploads, text, binary) are typed, and the implementation package, the tests and .openapi-generator-ignore are
    never overwritten. Configured under commands.generate.server_fastapi.

  • generate client python generates a Python client of an OpenAPI document, built on httpx (or httpx2) and Pydantic 2:
    Client and AsyncClient classes with one resource per tag (client.pets.list_pets()), Pydantic models with
    Python field names, tagged unions for discriminators and Input variants for readOnly/writeOnly properties,
    all parameter styles, JSON, form, multipart, text and binary bodies, typed errors parsed with the documented schemas,
    retries with backoff honoring Retry-After, per-request options, raw and streaming responses, server-sent events,
    server variables, and authentication by security scheme, including the OAuth 2.0 client credentials flow. The code
    passes mypy --strict. Configured under commands.generate.client_python.

  • generate client java generates a Java client of an OpenAPI document as a Maven project (Java 17, Spring Framework
    and Jackson versions from the Spring Boot BOM, without Spring Boot): an ApiClient on Spring's RestClient
    (--library restclient, the default) or RestTemplate (resttemplate) with one class per tag, whose operations have
    op(...), opWithHttpInfo(...), opStream(...) (a lazy Stream of text/event-stream and JSON Lines items) and
    opWith<MediaType>(...) methods for further request media types (updateShipmentWithJsonPatch); every parameter
    style, JSON-encoded content parameters, JSON, JSON Lines, form, multipart (Resource parts) and binary bodies,
    QUERY and other methods, operation and path servers, credentials per security scheme (bearer, basic, API keys in
    headers, queries and cookies) applied to the operations requiring them, and ApiException/ProblemDetailsException
    (RFC 9457) for errors; x-internal operations are left out. --library feign and --library http-interface
    generate Spring Cloud OpenFeign and Spring HTTP interface clients. Configured under commands.generate.client_java.

  • generate server express generates an Express 5 server stub in TypeScript from OpenAPI 3.x documents: typed handler
    interfaces per tag, implemented in files of your own, and createRouter(handlers, options), a router which checks
    security requirements with security handlers per scheme, decodes parameters in all OpenAPI styles and converts them
    to the types of their schemas, parses bodies, validates requests (and optionally responses) with Ajv or with
    generated validators without dependencies (validation), answers errors with RFC 9457 problem details and
    operations without handlers with 501. It can include the document and an example server. Configured under
    commands.generate.server_express.

  • generate server orpc generates a TypeScript server based on oRPC (https://orpc.dev) from an OpenAPI document: Zod
    schemas, a procedure contract per operation with its route, input, output and type-safe errors (one per 4xx/5xx
    response, sent with the response body of the document), handler stubs, and a Node.js server serving the procedures
    with oRPC's OpenAPIHandler and their OpenAPI reference. Inputs use oRPC's compact structure unless the request
    needs the detailed one, parameters are converted from strings, and operations with several success responses or
    response headers return status, headers and body. Handlers and the server files are written once, so regenerating
    keeps them. Targets oRPC 1, or oRPC 2 (beta) with orpc_version: 2. Configured under
    commands.generate.server_orpc.

  • generate server aspnet generates an ASP.NET Core server in C# built on Minimal APIs, for .NET 8 to 10 and
    without NuGet packages: records and enums of the schemas, one interface per group of operations whose methods return
    Results<...> unions of typed results (generated result types cover statuses TypedResults lacks), endpoints
    binding path, query, header and cookie parameters (array styles included) and JSON, text, binary, form and multipart
    bodies, and a project with Program.cs and stub implementations written only when missing. oneOf with a
    discriminator becomes [JsonPolymorphic] records, enums keep the values of the document, an endpoint filter
    validates requests against the constraints of their schemas (400 validation problems), and operations with security
    requirements call RequireAuthorization(). layout: sources writes only the sources, for existing projects.
    Configured under commands.generate.server_aspnet.

  • apigenie-mock --proxy-to http://host:port with an OpenAPI document is a validating proxy for contract testing: it
    forwards every request to the real server and checks the request and the server's response against the document
    (parameters, bodies, security, statuses, media types, headers). Violations carry stable checks such as
    response.body.incompatible and show up in the log, in X-Apigenie-Mock-Violations-Detail and at
    GET /__apigenie/contract; --strict rejects bad requests (422) and replaces bad responses (502). The mock counts
    the operations, request bodies and responses the traffic covered, and writes --report (JSON) and --report-junit
    when it stops; --fail-on and --min-coverage make it exit with 5. Configured under proxy and contract.

  • overlay command applies OpenAPI Overlays (versions 1.0, 1.1 and 1.2 of the specification) to an OpenAPI document,
    or to any JSON or YAML document: apigenie overlay INPUT --overlay OVERLAY, with --overlay repeated to apply
    several overlays in order. Updates, copies and removals follow the merge rules of the specification, reusable actions
    are supported, YAML comments are kept, and actions that select nothing are reported as warnings. --validate only
    checks the overlays, with the line and column of each issue. Targets are RFC 9535 JSONPath queries, functions
    (length(), count(), match(), search(), value()) included. The openapi_overlay WebAssembly module exports
    the same apply and validate.

  • generate server go generates a Go server for the net/http.ServeMux of Go 1.22 from an OpenAPI 3.x document, using
    the standard library only. Names and layering follow oapi-codegen: ServerInterface receives bound parameters,
    StrictServerInterface request and response objects (typed headers, statuses, JSON, form, multipart, text and binary
    bodies). Types carry Validate() methods, and parameters and bodies are validated before the handlers run, with RFC
    9457 problem details for failures; oneOf/anyOf become structs with one field per variant, optional nullable
    properties Nullable[T]. Patterns end with {$} where needed, and the patterns http.ServeMux can't register together
    share one that dispatches to the most specific operation. A SecurityHandler and middlewares run before parameters
    are bound. Configured under commands.generate.server_go.

  • generate schema zod generates Zod (v4) schemas, with their inferred TypeScript types, from the root schema and the
    $defs of a JSON Schema document (drafts 4 to 2020-12), or from the component schemas of an OpenAPI 3.x, Swagger 2.0
    or AsyncAPI document. Objects follow JSON Schema and keep unknown properties unless additionalProperties says
    otherwise; formats, numeric and string constraints, tuples, patternProperties, not, if/then/else and
    dependencies are validated, discriminated unions are detected, and recursive schemas become getters. Configured under
    commands.generate.schema_zod.

  • generate client ws and generate server ws generate TypeScript code from the WebSocket channels of AsyncAPI 3.x
    documents: a client with one class per channel (browsers and Node.js, no dependencies) and a Node.js server built on
    the ws package, with session classes and handler interfaces. Payloads, address parameters and the query of the
    WebSocket binding are typed; received messages get handlers of their own when a property with a constant value tells
    them apart. The server implements the described application and the client its counterpart, unless the
    perspective option says otherwise. Configured under commands.generate.client_ws and commands.generate.server_ws.

  • format --check reports the files that formatting would change, one path per line, and exits with 1 when
    there are any, without writing anything.

  • GitHub Action (src/github_action, not published yet) that installs the CLI on Linux, macOS and Windows
    runners and runs lint, format --check or diff (against the pull request's base), with annotations on the
    files and a job summary. With sarif: true, lint issues are also uploaded to GitHub code scanning; on pull
    requests, the diff report is posted as a comment that later runs update in place.

  • sarif formatter of lint: SARIF 2.1.0 for GitHub code scanning and other dashboards, with paths relative to the
    current directory and fingerprints based on JSON pointers, so that issues are tracked across runs.

  • apigenie-mock, a mock server for OpenAPI 3.0 and 3.1 documents, installed with apigenie by every package and
    published as the mykulyak/apigenie-mock Docker image. It answers with the document's examples or with data
    generated from its schemas, validates requests (422 with problem details) and its own responses, checks security
    requirements, follows Prefer headers (code, example, dynamic, delay, drop, scenario), simulates
    latency, jitter, dropped connections and bandwidth limits, and logs every exchange as text or JSON lines. Scenarios
    force error states from a configuration file (apigenie-mock.yaml or commands.mock), x-apigenie-mock document
    extensions or an admin API under /__apigenie, which also reloads, reseeds and stops the server. --watch reloads
    the document and the configuration when they change. Schemas can pick faker functions with x-faker.

  • apigenie-mock serves AsyncAPI 3.x documents: WebSocket clients of a channel get its send operations' messages on a
    schedule and their messages are checked against its receive operations and answered with their replies; HTTP
    channels take and answer messages; an in-house MQTT 3.1.1 and 5 broker serves the channels of mqtt servers.

  • apigenie-mock serves the gRPC services of .proto files over cleartext HTTP/2, on the same port as HTTP:
    unary and streaming methods answered from YAML or JSON stub files (--stubs, grpc.stubs) with request and
    metadata matchers, templates, delays and error statuses with google.rpc details, or with messages generated from
    the response types. It honours deadlines and message limits, follows x-apigenie-mock-* metadata, applies
    scenarios (grpc_status, grpc_message) and scripts, serves server reflection (v1 and v1alpha) and health checks,
    proxies unanswered calls to an upstream server (--proxy-to) and records them as stub files (--record-dir). The
    admin API manages stubs and has the call history and a verify endpoint under /__apigenie/grpc. Imports are
    looked up in --proto-path directories and among the embedded well-known, google/api and google/rpc files.

  • apigenie-mock also answers OpenAPI documents over cleartext HTTP/2 (prior knowledge).

  • apigenie-mock serves GraphQL schemas (.graphql, .graphqls, .gql) at /graphql: GET, POST and batched
    requests per GraphQL over HTTP, validated against the schema with the rules and messages of graphql-js, executed
    with generated data (by type, field name and custom scalar name, or as graphql-faker's @fake, @examples and
    @listLength and the mock's @mock directives say), full introspection, GraphiQL and the SDL. Entities (types
    with an id) keep their values across requests, and user(id:), users, usersConnection (Relay) and
    createUser, updateUser, deleteUser-like fields read and change them. Examples (graphql.examples, example
    files, <schema>_examples/) answer operations or fields, cut to the selection set and completed with generated
    values; scenario rules match operations and root fields and inject errors at field paths. Subscriptions are served
    over WebSocket (graphql-transport-ws and the legacy graphql-ws) and server-sent events. Configured under
    graphql.

  • apigenie-mock runs JavaScript hooks (--script, scripts): onRequest answers requests, onResponse changes
    responses and their simulated delays or drops, onMessage changes or drops AsyncAPI messages, onGraphQL
    answers GraphQL operations, with state kept
    between requests, logging, seeded random numbers, faker functions and scenarios.

  • Linter validates documents against the OpenAPI schema, and more rules support autofixing, including the new
    schema-no-optional-nullable-properties rule.

  • diff command (openapi-diff) and the HTML documentation generator are available again.

  • diff severities are configurable per context: request and response rule overlays (callbacks and webhooks
    swap them), overrides for single locations, conditions such as if: required, and add_first_item /
    remove_last_item rules. Schema properties are compared, respecting readOnly and writeOnly.

  • diff detailed reports describe each change in all formats.

  • diff command compares AsyncAPI 3.x documents: servers, channels, operations, messages and their payloads and
    headers, security schemes, bindings (property by property for HTTP, WebSockets, Kafka, AMQP and MQTT) and
    components, with the same reports, formatters, exit status and --update-version as OpenAPI documents. The
    severity of a message change depends on whether the application sends or receives the message (send and
    receive rule overlays). Configured under commands.diff.asyncapi.

  • diff command compares Protobuf (proto3 .proto) files: package, imports, options, messages, fields (matched by
    their numbers), oneofs, enums, services, methods, extend blocks, reserved numbers and names, and comments, with the
    same reports, formatters and exit status as OpenAPI documents. Type names are resolved before they are compared,
    and removing a field whose number the new file reserves is not breaking. Severities can depend on reserved,
    deprecated and wire_compatible conditions, and options are configured by their names. Configured under
    commands.diff.protobuf.

  • diff command compares Swagger 2.0 documents: host, base path, schemes, media types, paths, operations,
    parameters (matched by location and name, the body parameter by location), responses, headers, schemas
    (following references to definitions), security definitions and requirements, and tags, with the same reports,
    formatters, exit status and --update-version as OpenAPI documents. Body parameters and consumed media types get
    the request rules, responses and produced media types the response ones, and definitions the stricter of the
    two. Configured under commands.diff.swagger.

  • diff command compares GraphQL schemas (.graphql, .graphqls and .gql files): root operation types, types of
    every kind, fields, arguments, input fields, default values, interfaces, union members, enum values, directive
    definitions, applied directives and descriptions, with the same reports, formatters and exit status as OpenAPI
    documents. Type extensions are merged into their types, and operations are ignored. Severities follow graphql-js's
    breaking changes and can depend on required, compatible, deprecated and boolean conditions; directives are
    configured by their names. Configured under commands.diff.graphql.

  • changelog command builds the changelog of an OpenAPI file from its git history: one entry per commit or per
    release tag, or the history of each operation (--by operation, filtered with --operation), as stylish text,
    Markdown, HTML or JSON. Files the specification references are followed in each version.

  • changelog command builds the changelog of AsyncAPI 3.x files too: added, removed and changed operations, channels
    and servers, with the changes of a channel's messages shown under the operations using it, rated with the
    commands.diff.asyncapi rules. --operation selects AsyncAPI operations by id, by send/receive and channel
    address, or by channel address.

  • changelog command builds the changelog of Protobuf (.proto) files too: added, removed and changed methods
    (named Service.Method), messages, enums, services and extensions, package changes shown like version changes,
    rated with the commands.diff.protobuf rules. The file is compared on its own, without the files it imports.
    --by operation groups the changes by method, and --operation selects methods by full name, method name or
    service name.

  • Swagger 2.0 input support.

  • changelog command builds the changelog of Swagger 2.0 documents too: added, removed, deprecated and changed
    operations, with the changes of a path item shown under its operations, and the host, base path, schemes, media
    types and security of the API as metadata, rated with the commands.diff.swagger rules. Files the specification
    references are followed in each version.

  • changelog command builds the changelog of GraphQL (.graphql, .graphqls, .gql) schema files too: added,
    removed and changed operations (the fields of the root operation types, named like Query.books), scalars, object
    types, interfaces, unions, enums, input objects and directive definitions, with changes of the root operation
    types, the schema description and the schema directives as metadata, rated with the commands.diff.graphql rules.
    The file is compared on its own. --by operation groups the changes by operation, and --operation selects
    operations by full name, field name, root type name or operation type (query, mutation, subscription).

  • bundle command bundles Swagger 2.0 documents and the local files they reference into a single file: referenced
    schemas, parameters and responses become entries of definitions, parameters and responses, and referenced
    path items take the content of their files.

  • bundle command bundles AsyncAPI 3.x documents and the local files they reference into a single file. Root
    servers, channels and operations kept in other files take the content of those files, so that operations still
    refer to their channels and channel messages; other referenced objects become components. Schemas in other formats,
    such as Avro, are copied as they are, and references by URL are kept.

  • bundle command bundles Protobuf (.proto) files: the input file and the messages, enums and extensions it uses
    from the files it imports (searched in the -I/--proto-path directories) are combined into one proto3 file.
    Declarations from other packages are renamed with a prefix made from their package, and well-known type imports
    are kept.

  • format command formats AsyncAPI 3.x documents, configured under commands.format.asyncapi.

  • i18n command extracts the texts of AsyncAPI 3.x documents for translation: the titles, summaries and
    descriptions of servers, channels, operations, messages, schemas and the other objects, keyed by their JSON
    pointers.

  • i18n command extracts the leading comments of Protobuf (.proto) files for translation, keyed by the fully
    qualified name of the message, field, oneof, enum, enum value, service or method they document; enum values are
    keyed under their enum, and the comment of the file (that of its syntax statement) under the package name.

  • i18n command extracts the descriptions of GraphQL (.graphql, .graphqls, .gql) files for translation, keyed
    by full name: the schema (schema), types, fields, arguments, input fields, enum values and directives by their
    schema coordinates (e.g. Query.search(text:), Genre.POETRY, @key), operations and their variables (e.g.
    query FindBooks, query FindBooks($text:)) and fragments (e.g. fragment BookSummary).

  • format command formats Swagger 2.0 documents, configured under commands.format.swagger.

  • format command formats GraphQL schemas and operations (.graphql, .graphqls, .gql) in the layout of Prettier,
    keeping all comments, and optionally sorts definitions and the members of types. Configured under
    commands.format.graphql.

  • lint command lints AsyncAPI 3.x documents with 31 rules (ported from the OpenAPI ones where they apply, plus
    channel-parameters-defined, channel-addresses-unique and server-hosts), rulesets, custom rules and autofixes,
    configured under commands.lint.asyncapi.

  • lint command lints Swagger 2.0 documents with 46 rules (ported from the OpenAPI ones where they apply, plus
    host-defined, schemes-secure, media-types-defined and swagger-validation, which reports the specification
    violations found by the Swagger validator), rulesets, custom rules and autofixes, configured under
    commands.lint.swagger.

  • lint command lints Protobuf (proto3 .proto) files with 39 rules modelled on buf's: naming conventions, packages
    (versions, directories, consistent language options, import cycles between packages), imports (unresolved,
    unused, public, weak, cycles, order), enums, services and RPCs, comments and spell checking. Imports are looked up
    in --proto-path directories, the import_paths of the configuration and the directories above the file, with
    the well-known google/protobuf files built in. --fix removes unused imports and sorts imports; an
    // apigenie-lint-disable <rules> comment disables rules for a declaration. Configured under
    commands.lint.protobuf with the recommended (default), strict and all rulesets.

  • lint command lints GraphQL schemas and operations (.graphql, .graphqls, .gql) with 87 rules modelled on
    graphql-eslint, graphql-schema-linter and Apollo's schema linter: the type system and operation rules of the
    specification, naming conventions, descriptions, deprecations (reasons, deletion dates), schema design (root types,
    mutations and payloads, unreachable types, identifiers, @oneOf, circular input types), the Relay connection
    conventions, ordering, spelling, and operations checked against the schema (unknown fields, types and arguments,
    required arguments, deprecated fields, selection depth, identifier selections). Operations are checked against the
    files named by --graphql-schema or by the schema option, or against the type system of their own document. A # apigenie-lint-disable <rules>
    comment disables rules for a definition. Configured under commands.lint.graphql with the recommended (default),
    strict, all and relay rulesets; --fix doesn't apply to GraphQL files.

  • Minimal telemetry.

  • Linter rules reasoning about schemas: schema-no-contradictions (constraints rejecting every value, and
    properties forbidden by an allOf member with additionalProperties: false), schema-oneof-no-overlap (oneOf
    branches a single value matches, shown in the report), schema-required-properties-defined and
    schema-conditional-effective (if/then/else without effect), all in the recommended ruleset, and
    patch-request-body-partial (required properties in PATCH bodies) in the strict ruleset.

  • Official release binaries for macOS (arm64), Linux (x64, static, runs on any distribution) and Windows (x64),
    plus .deb and .rpm packages, a Homebrew formula, per-platform npm packages and a versioned Docker image.

  • generate server express and generate client fetch follow discriminator.defaultMapping (OpenAPI 3.2;
    x-defaultMapping in 3.0 and 3.1). Express validates such a oneOf by the discriminating property: with Ajv as an
    if/then/else chain that ends with the default schema, with validation: generated by a dispatch reporting the
    same issues. A value whose property matches no mapping, or lacks it, is validated against the default schema instead
    of failing oneOf. The types of both targets get a type guard per member (isParcelShipment(value: Shipment)), the
    default member's taking the values no mapping matches. The fetch client's conformance snapshots cover OpenAPI 3.1 and
    3.0 too.

Changed

  • The documentation smoke run of the codegen conformance suite is generate docs (test_docs_bundle) instead of
    generate doc html, and the e2e/generate_doc_html benchmark cases are e2e/generate_docs.

  • apigenie test import writes the credentials it finds (bearer tokens, basic credentials, API keys, OAuth 2 client
    secrets and passwords) to a generated http-client.private.env.json instead of http-client.env.json, which keeps
    the other variables and no secret; apigenie test reads both. The sensitive-environment warning names the private
    file.

  • The web components read AsyncAPI documents with the asyncapi WebAssembly module, as they read GraphQL and
    Protobuf: set asyncapi-wasm-url on <apg-spec> or <apg-api-reference>, or call configureAsyncApiEngine(url).
    npm run prerender takes --asyncapi-wasm. There is no JavaScript reader for AsyncAPI any more; without the module,
    AsyncAPI documents fail to load with a message saying what to set. The views are unchanged.
    @mykulyak/apigenie-asyncapi-view reads the module's documentation model; its parse and traits modules are
    gone. Server-rendered pages embed the model, so hydration needs no module.

  • The JSON contract reports of apigenie-mock --report, GET /__apigenie/contract and apigenie test --report give
    each OpenAPI operation the JSON pointer of the operation in the document (e.g. /paths/~1pets/get).

  • Internal: swagger_convert returns a source map with each conversion, from the JSON pointers of the result to those
    of the Swagger 2.0 document.

  • apigenie-mock --proxy-to with a .proto file logs request violations instead of failing the call with
    INVALID_ARGUMENT, as the OpenAPI, GraphQL and AsyncAPI proxies do; --strict or grpc.validation.request: enforce
    restores it, and a request is then checked before it reaches the upstream (an always-mode proxy forwarded it first).
    A mock without --proxy-to keeps enforcing requests, and now also rejects a request that misses a field marked
    [(google.api.field_behavior) = REQUIRED]. A non-200 HTTP answer of the upstream ends the call with the
    status gRPC clients make of it (UNAVAILABLE for 503) instead of always UNAVAILABLE, and an upstream answer without
    grpc-status ends as UNKNOWN instead of OK.

  • --report and --report-junit of apigenie-mock are accepted for .proto files, and /__apigenie/contract
    answers for them.

  • The requester of generate server aspnet's Kafka code (AsyncAPI) waits for replies on the runtime's new
    KafkaReplies, which generate client csharp shares; its behaviour is unchanged. The OpenAPI configurations of
    generate client csharp and generate server aspnet ignore their asyncapi section instead of rejecting it as an
    unknown option.

  • generate server aspnet (OpenAPI) writes the recursive DataAnnotations validation of ValidationFilter as
    Infrastructure/ModelValidator.cs, which the AsyncAPI Kafka application uses for its messages too; the behavior
    is unchanged.

  • apigenie and apigenie-mock link Mbed TLS 3.6 (Apache-2.0), the first runtime library from vcpkg; credits and
    license --library mbedtls list it. The release binaries grow by about 0.9 MB (macOS arm64: apigenie +3.5%,
    apigenie-mock +8.2%). The Docker images now include Alpine's CA certificates.

  • apigenie-mock --proxy-to no longer refuses https:// and wss:// targets with exit status 2, and the 426 answer
    to gRPC over HTTP/1.1 on a TLS port says to ask for h2 by ALPN instead of offering Upgrade: h2c.

  • generate server spring is built on openapi_generator_java, the Java layer it shares with generate client java,
    whose Feign and HTTP interface writers now generate its spring-cloud and spring-http-interface libraries; their
    output is unchanged. Models get defaultImpl from discriminator.defaultMapping (x-defaultMapping before 3.2),
    name implicit discriminator mappings after the const value of the members (person instead of Person), no
    longer require the properties of anyOf/oneOf alternatives (Person and Company required both email and phone
    of ContactChannels), and treat an allOf with only a reference to a oneOf interface as that interface (3.0
    documents produced a class extending an interface).

  • generate server go: an anyOf or oneOf whose members only list required properties no longer makes a union of
    untyped values, so allOf schemas holding one are merged into structs (instead of any) and Validate() checks
    the alternatives; a discriminator's defaultMapping (x-defaultMapping in 3.0 and 3.1) decodes unknown values as
    its fallback variant, and an implicit mapping also accepts the const the variant gives the property. The runtime's
    request binders moved from runtime_params.gen.go to a new runtime_bind.gen.go.

  • The OpenAPI library reads a media type's itemSchema and a discriminator's defaultMapping (3.2), and their
    x-itemSchema and x-defaultMapping forms in 3.0 and 3.1 documents.

  • generate server aspnet and generate client csharp share their C# models (src/openapi_generator_csharp). The
    server's output changes in two ways: the implicit discriminator value of a oneOf variant is the const of its
    discriminator property when it has one (e.g. "person" instead of the schema name "Person"), and a oneOf or
    anyOf whose members map to one C# type has that type (e.g. List<string> for strings of the ipv4 and ipv6
    formats, instead of List<object>).

  • The contract report of apigenie-mock (gate, JSON and JUnit) moved into the mock and openapi_mock libraries,
    shared with apigenie test; its output is unchanged.

  • format keeps the YAML comments of OpenAPI, Swagger and AsyncAPI documents (at the top and the end of the file,
    above keys, at the end of lines, inside sequences and between entries); comments move with their keys when
    properties are sorted. Before, every comment was dropped, and format --check reported commented files that were
    formatted.

  • lint --fix keeps the YAML comments of the OpenAPI, Swagger and AsyncAPI documents it rewrites, including those of
    the properties a fix replaces, instead of dropping them all.

  • format writes a Protobuf comment that follows a declaration on the next line (and that protoc attaches to it)
    on its own line again, instead of moving it to the end of the declaration's line.

  • i18n has two subcommands: i18n extract extracts texts, as i18n did, and i18n apply applies translations.
    apigenie i18n FILE --output DEST becomes apigenie i18n extract FILE --output DEST, which also accepts -o.

  • apigenie-mock --stubs with a GraphQL schema or an AsyncAPI document exits with status 2 instead of being ignored;
    stubs answer the calls of a .proto file and, now, the operations of an OpenAPI document.

  • lint exits with status 1 when it reports issues of severity error (those remaining after --fix), so CI
    jobs fail on them; warnings keep the exit status at 0.

  • The CLI binary is about 2.8 MB (14%) smaller: the test-data generator's string tables (names, addresses, words and
    the like) are stored compressed and decoded when first used, instead of as pointer tables.

  • The built-in English spelling dictionary is stored compressed (about 290 KB less in the binary) and decoded
    only when the first spell-check rule runs; the decoded bytes are released once the dictionary is parsed.

  • The third-party license texts shown by license --library are stored compressed and decoded only when one is
    printed.

  • format reports files that are neither OpenAPI nor AsyncAPI documents and leaves them untouched,
    instead of writing empty output.

  • Parse errors in JSON and YAML input now report why and where the input cannot be parsed.

  • lint with several input files writes a single report for the json, checkstyle, junit, html, sarif and
    tap formatters, instead of one document per file.

  • diff exit status and --update-version consider all changes, whatever the report shows, and a fixed severity
    of a node caps the severities of changes inside it (e.g. adding an optional parameter is non-breaking).

  • diff --update-version changes only the version in the file, keeping its formatting.

  • diff configuration is validated: unknown node types, properties and severities are reported.

  • generate server spring builds Java sources with a syntax tree instead of text templates. The generated code
    is the same, but imports are sorted and blank lines and indentation are consistent.

  • unused-shared-component is enabled again in the recommended (warning), strict and all rulesets, and skips
    documents without operations, which are libraries of components for other documents.

  • schema-no-optional-nullable-properties recognizes OpenAPI 3.0 nullable: true, referenced nullable schemas and
    anyOf/oneOf null branches, finds required in allOf members, and skips PATCH and merge-patch bodies, where
    null clears a value (option ignorePatchBodies).

  • spell-check (OpenAPI and AsyncAPI) now checks spelling: it reports each misspelled word of titles, summaries
    and descriptions with suggested corrections, using a built-in English dictionary, and skips code, URLs,
    identifiers and acronyms. Options words (extra words), suggestions and dictionary/affix (any Hunspell
    dictionary) are optional. The rule moved from the recommended ruleset to strict and all.

  • Internal: the Swagger 2.0 to OpenAPI 3.2 conversion behind convert --to openapi32 moved from the CLI into its own
    library, swagger_convert, which also reports what each conversion approximates or drops (not shown by the CLI
    yet). The output of convert is unchanged.

  • Internal: a release gate (release_gate.yaml) runs every test on Linux, Windows and macOS, the tests that build
    generated code with Java, Go, .NET and Python, the RealWorld demo, codegen conformance Levels 2 and 3 and the
    WebAssembly build; a cli-* tag only gets its draft release once the gate passed on the tagged commit.

Removed

  • generate doc html, the Astro documentation project it generated and the @mykulyak/api-genie-doc-html-template
    package it depended on, with the commands.generate.doc_html configuration section (see Upgrading). Internal:
    openapi_generator_doc_html and code_morph_astro.

Fixed

  • apigenie-mock --license without a library name prints API Genie's license instead of the usage: an option whose
    value is optional counted as given only with a value.
  • generate server spring reads request bodies typed by a oneOf without discriminator (JSON Patch operations, Carpet
    Express's recursive SearchFilter): such interfaces had no type information, so Jackson couldn't instantiate them
    and the request answered 500. The interface now names a Deserializer built on the generated OneOfDeserializer,
    which reads the one member the value matches: a member that declares all its properties (or takes additional
    properties), reads it and, with Bean Validation, is valid. A value matching no member, or several, is a 400.
    useDeductionForOneOfInterfaces=true keeps Jackson's deduction. Strings with format: uri (java.net.URI) no
    longer get @Pattern or @Size in generate server spring and generate client java: Bean Validation can't check
    them on a URI and threw UnexpectedTypeException (the server's createWebhookSubscription answered 500); their
    pattern isn't checked.
  • The Pydantic models of generate client python, generate server faststream and the Python Kafka client check
    pattern: Annotated[str, matching(r"...")], a validator of _models.py compiling the pattern with Python's re
    when a value is first checked (Pydantic's default engine rejects look-arounds, back-references and large \w
    repetitions, which would break the model). Named string schemas keep their constraints in their aliases, e.g.
    ShipmentId: TypeAlias = Annotated[str, matching(r"^shp_[0-9A-Za-z]{24}$")]; a pattern re can't compile, such as
    one using \p{L}, isn't checked.
  • generate server faststream: published messages and replies no longer carry null for optional fields that weren't
    set, which their schemas don't allow. The publish functions and the subscribers' replies send payloads through the
    runtime's new encode_message() (the fields that were set), instead of letting FastStream serialize the models with
    every field. Subscribers of operations with a static reply channel now return a KafkaResponse, RabbitResponse or
    MQTTResponse, and their reply publisher states the reply's schema (schema=).
  • The code of generate client ws and generate server ws passes typescript-eslint's recommended type-checked rules:
    options and handler interfaces that would be empty are type aliases, the client runtime's
    WebSocketLike.addEventListener has one overload per event instead of an any listener, and the shared AsyncAPI type
    mapper no longer writes unknown into unions ([key: string]: unknown) or intersections (an anyOf of required
    lists).
  • The validators of generate server express (validation: functions) import pointerToken only when a generated
    function uses it, so object schemas with additionalProperties: true no longer leave an unused import.
  • Generated values (apigenie-mock responses and messages, examples) satisfy an object schema's oneOf/anyOf next
    to its properties, such as anyOf: [{required: [phone]}, {required: [email]}]: one alternative is picked and
    what it requires is generated. The alternatives used to be ignored, so such objects could lack every property they
    ask for.
  • apigenie-mock: the problems of an x-apigenie-mock extension name it by a well-formed JSON pointer
    (/paths/~1pets/get/x-apigenie-mock, not /paths//pets/get/...), and by its line when the value has no position
    of its own.
  • apigenie-mock generates AsyncAPI messages whose schemas use AsyncAPI's string discriminator or an externalDocs
    given by $ref: such documents made every message without an example fail with "the payload has no schema values
    can be generated from". A reply whose message has its correlationId in the payload now carries the request's value
    (Carpet Express's requestPickup gets a pickupConfirmed with its requestId).
  • apigenie-mock --proxy-to ws:// checks the server's reply to a client message of a request/reply operation against
    the reply's messages and its correlationId (message.reply.uncorrelated), instead of reporting it as
    channel.send.undeclared on a channel without send operations (ADR-110).
  • generate server faststream no longer fails with "The message schemas can't be mapped to Python types" when a payload
    schema's externalDocs is a $ref, as the AsyncAPI fixture's CloudEvent has: the reference is followed.
  • The AsyncAPI contract report counts the requests of HTTP channels, mocked or proxied, as messages of their
    operations.
  • generate client csharp: the generated project compiles again: the client of the API is registered with
    AddHttpClient<TClient, TClient>(factory), as AddHttpClient<TClient> has no factory overload and bound the lambda to
    its configuration callback (CS1503). Unions read by the generated discriminator converters no longer carry
    [JsonPolymorphic]/[JsonDerivedType], which System.Text.Json rejects next to a custom converter ("does not support
    metadata writes or reads") when sending or reading a oneOf with a discriminator.
  • generate client csharp and generate server aspnet: properties with a default value are settable instead of
    init-only, because the System.Text.Json source generator of .NET 8 assigns every init-only property and replaced the
    default of an absent one with 0/false/null; decimals described as strings (type: string, format: decimal) are
    written as JSON strings.
  • generate client python: form body fields whose encoding sets style or explode are written like query parameters
    of that style (deepObject: hints[building]=rear) instead of as JSON text. The package passes ruff's default rules:
    __all__ lists are sorted as RUF022 expects, and the runtime uses X | Y unions and Self.
  • generate server express with validation: generated: objects without declared properties (maps), or with only
    patternProperties, no longer get validators with constant conditions (if (!(false)), false || ...), which
    failed ESLint's no-constant-condition. The codegen conformance suite's Level 2 now also type-checks and lints a
    validation: generated build.
  • generate client fetch: properties of application/x-www-form-urlencoded bodies whose encoding sets style or
    explode are written like query parameters of that style (deepObject: hints%5Bbuilding%5D=rear, also
    pipeDelimited, spaceDelimited and unexploded form) instead of as JSON text; the other object properties stay
    JSON. The runtime no longer calls String() on values of unknown type, so it passes typescript-eslint's
    no-base-to-string.
  • generate server express routes QUERY and COPY operations (OpenAPI 3.2): their routes were typed with a method
    the runtime's HttpMethod type lacked, so the generated package didn't compile. An empty form field of a nullable
    property (location= for oneOf: [GeoPoint, {type: null}]) is read as null instead of failing validation, and the
    runtime passes typescript-eslint's recommended type-checked rules.
  • generate client fetch, generate server express and generate server orpc: anyOf/oneOf alternatives that only
    add constraints (anyOf: [{required: [email]}, {required: [phone]}]) no longer add & unknown to the type.
  • generate server aspnet: an empty form field for an object (location=, how form style writes an empty or null
    value) is read as null instead of failing to parse as JSON with 400.
  • generate server spring: a @lombok.* annotation in a model's x-class-extra-annotation drops the members Lombok
    generates for that model and adds Lombok to the pom, as additionalModelTypeAnnotations does; before, the model kept
    its own equals/hashCode next to @lombok.EqualsAndHashCode and the project didn't build without Lombok. Deprecated
    parameters no longer get @Deprecated, which has no effect on parameters (javac -Xlint warns since JDK 21); the
    deprecation stays in @Parameter(deprecated = true).
  • generate client python and generate server faststream: allOf parts with oneOf/anyOf alternatives that only
    add constraints, such as Carpet Express's ContactChannels (an email or a phone), are merged like other object
    parts, so Person and Company are models instead of Any. Discriminated unions dispatch on the mapping, on the
    schema names of the members it leaves out (the implicit mapping) and on the value each of those members fixes the
    property to with const or a single enum value (partyType: person of a schema named Person). Values whose tag
    is missing or unknown are read as the discriminator.defaultMapping schema (x-defaultMapping in OpenAPI 3.0 and
    3.1), which joins the union if it isn't a member; before, they matched no model. The unions keep their callable
    pydantic.Discriminator, as Field(discriminator=...) can neither fall back nor take several tags per model. The
    codegen conformance suite checks generate client python against the OpenAPI 3.1 and 3.0 fixtures too.
  • generate server fastapi passes the codegen conformance suite's mypy, ruff and runtime checks without known
    failures, on the OpenAPI 3.2, 3.1 and 3.0 fixtures:
    • Discriminator tags follow the Python models: a member that fixes the property with const or a single enum
      value gets that value (party_type: Literal["person"] for a schema named Person), where the implicit mapping
      made it Literal["Person"] and rejected valid parties. A union with a discriminator.defaultMapping
      (x-defaultMapping in OpenAPI 3.0 and 3.1) dispatches with a callable Discriminator() that reads values with a
      missing or unknown tag as the default schema, which joins the union if it isn't a member.
    • RootModel subclasses have their type argument (RootModel[int | str]; a forward reference in a cycle), which
      mypy --strict asked for.
    • A request body with several JSON media types, such as application/merge-patch+json and
      application/json-patch+json, is validated against the schema of the request's Content-Type (415 for another
      one); the route took only the first media type's schema. The body parameter is the union of the schemas and the
      served OpenAPI document lists every media type.
    • Integer enums in parameters and form fields convert the request's text (dpi=300); Literal[203, 300, 600]
      rejected every value.
    • Multipart file parts described with contentMediaType or contentEncoding: binary (OpenAPI 3.1 and 3.2), not
      only format: binary, are UploadFiles, and arrays of them list[UploadFile].
    • Imports are sorted the way Ruff's isort rules expect (case-insensitive, numbers by value, long single-name imports
      wrapped), and the imports at the end of modules of a cycle no longer carry a # noqa: E402 that Ruff reports as
      unused.
  • apigenie test --generate sends multipart file parts (format: binary, contentMediaType or
    contentEncoding: binary) with a file name and the Content-Type of their encoding, and an array as a part per item;
    servers that only take parts with a file name as files, such as FastAPI's and ASP.NET Core's, rejected the generated
    requests.
  • generate client python and generate server faststream: an object schema with properties of its own and oneOf
    or anyOf alternatives that are objects (each narrowing a property or requiring others) becomes a union of one
    model per alternative with the object's properties merged in. The properties were lost (a union of classes holding
    only the alternatives' properties), and anyOf of required lists, such as "an email or a phone", was Any.
  • The CLI no longer writes .apigenie.telemetry in the current directory; set
    APIGENIE_TELEMETRY_FILE to keep a local telemetry log.
  • apigenie-mock and apigenie test type the fields of form and multipart bodies (and deepObject and delimited
    parameters) whose properties come from allOf members, references included: residential=false of a body
    allOf: [$ref Address, {...}] is the boolean false, not the string. They were validated as strings, so valid
    requests were reported or rejected with 422.
  • YAML output quotes strings that YAML 1.1 parsers (PyYAML, SnakeYAML, go-yaml v2) read as booleans, numbers or
    merge keys: yes, No, ON, off, y, N, 0b101, 1_000, 1:30, << and the like. Before, bundle,
    overlay, lint --fix, convert and format with the best-fit style wrote them plain, so other tools read
    enum: [yes, no] as booleans and 1:30 as 90.
  • apigenie-mock validates requests and responses whose schemas refer to themselves (trees, nested filters, recursive
    oneOfs). They were accepted without any check, in OpenAPI and AsyncAPI documents alike. The lint rules
    schema-no-contradictions and schema-oneof-no-overlap now analyze such schemas too.
  • OpenAPI 3.2 documents: examples written with dataValue and media types that refer to components/mediaTypes are
    read. Generators no longer drop them (Spring rendered such examples as null, Go typed such problem responses as
    any), and apigenie-mock answers with those examples.
  • generate server fastapi routes the OpenAPI 3.2 query method and the methods of additionalOperations (such as
    COPY) with @router.api_route(..., methods=[...]). They were emitted as @router.query/@router.copy, which
    APIRouter doesn't have, so a server generated from a document with such an operation failed to import.
  • convert --to openapi32 converts the structure of Swagger 2.0 documents, not only their references: body and
    formData parameters become request bodies with the media types of consumes (files as multipart/form-data),
    collectionFormat becomes style and explode, response schemas, headers and examples move into content per media
    type of produces, global body parameters become components.requestBodies, and references to parameters and
    responses point into components. Schemas get type: file as binary strings, object discriminators, numeric
    exclusive bounds and x-nullable as a null type. Before, most converted documents could not be read (2163 of the
    2168 Swagger documents of the openapi-directory corpus convert into readable documents now, the others are invalid).
  • Many memory-safety and robustness issues in the parsers, bundler, reader and linter.
  • diff changelog reports rate added, removed and modified operations by their own changes rather than their
    path's, report request body changes as such instead of as response codes, and no longer list a removed
    deprecated operation as deprecated.
  • generate server spring numbers enum constants whose names collide (e.g. the values +1 and -1, both named
    _1), like openapi-generator, so the generated models compile.
  • test reports a rejected certificate as such for wss://, mqtts:// and grpcs:// URLs whose host name has
    several addresses: it stops at the first address that answers instead of trying the others and reporting the
    last one's "Connection refused" (on macOS, localhost is 127.0.0.1 and ::1, and a server often listens on one).
  • The YAML and JSON writers report an alias of a collection that contains it as soon as they meet it again,
    instead of after expanding it to the depth limit, which overflowed the JavaScript stack of the WebAssembly
    build.
  • generate server spring with useSpringBoot4 no longer declares spring-boot-starter-restclient (or
    -webclient) twice, which Maven rejects as a duplicate dependency.