connect2axum-codegen 0.5.1

Protoc generators for REST, WebSocket, OpenAPI, and AsyncAPI wrappers over ConnectRPC services
Documentation
# connect2axum [![Crate]https://img.shields.io/crates/v/connect2axum]https://crates.io/crates/connect2axum [![Docs]https://docs.rs/connect2axum/badge.svg]https://docs.rs/connect2axum [![Build]https://github.com/nu11ptr/connect2axum/workflows/CI/badge.svg]https://github.com/nu11ptr/connect2axum/actions [![License]https://img.shields.io/crates/l/connect2axum]https://github.com/nu11ptr/connect2axum/blob/main/LICENSE

Generate REST and/or WebSocket endpoint wrappers over ConnectRPC services.
Additionally, generate OpenAPI docs for REST endpoints and AsyncAPI docs for
WebSocket endpoints.

## Install

```sh
cargo install --locked connect2axum-codegen
```

This installs:

- `protoc-gen-connect2rest`
- `protoc-gen-connect2ws`
- `protoc-gen-connect2openapi`
- `protoc-gen-connect2asyncapi`

`connect2axum` 0.4 and `connect2axum-codegen` 0.5 target Buffa 0.9 and
ConnectRPC 0.9. When upgrading from upstream versions before 0.9, regenerate
the Buffa, ConnectRPC, and connect2axum bindings together. Service implementations receive
`ServiceRequest<'_, Request>` for unary and server-streaming calls, and
`InboundStream<Request>` (items of `StreamMessage<Request>`) for client and
bidirectional streaming calls. Read stream-item fields through `.view()` or
the generated accessor methods.

Version 0.4 removes `JsonCompatibleView` and `json_compatible_view`. Use
`json_view` for response views with a ProtoJSON `Serialize` implementation,
or return an owned message. `json_owned_view` remains the input helper for
decoding incoming JSON into an `OwnedView`.

## Domain-owned Responses

An application can keep its own response types and borrow their fields only
while encoding. Implement ConnectRPC's `Encodable<Message>` for the domain
type and use `connect2axum::json_view` around a temporary Buffa view:

```rust
use buffa::bytes::Bytes;
use connectrpc::{CodecFormat, ConnectError, Encodable};
use flexstr::SharedStr;

// HelloReply and HelloReplyView are the generated message and view types.
struct Greeting {
    message: SharedStr,
}

impl Encodable<HelloReply> for Greeting {
    fn encode(&self, codec: CodecFormat) -> Result<Bytes, ConnectError> {
        connect2axum::json_view(HelloReplyView {
            message: self.message.as_ref(),
            ..Default::default()
        })
        .encode(codec)
    }
}
```

The stream owns each `Greeting`, so it can cross task/channel boundaries.
The view borrows its fields only during encoding; no generated owned
`HelloReply` or intermediate protobuf buffer is needed to produce JSON.
This does not require `SharedStr` to implement Buffa field traits because the
generated view uses `&str`.

`json_view` serializes JSON directly through the view's `Serialize` impl and
delegates other codecs to its `Encodable` impl. Enable Buffa JSON generation
for the view. Both implementations must represent the same protobuf message;
an arbitrary domain struct's derived serde is not necessarily ProtoJSON.
The same response item works with Connect/gRPC, REST, and JSON WebSocket
adapters. See the [WebSocket streaming example](examples/ws-streaming/src/lib.rs)
for a complete implementation and transport tests.

Return an owned message when registered protobuf extensions must appear in
JSON: Buffa's generated view serializer omits those extensions.
Direct view encoding can still allocate output buffers or temporary view
containers; it does not guarantee allocation-free serialization.

## Nested Fields

Path variables may bind a field inside singular messages, such as
`get: "/symbols/{datasource.symbol.ticker}"`. The rest of `datasource` still
comes from the body or query; the path value overrides only that field.

Query parameters accept dotted paths into nested messages, using protobuf or
JSON field names: `?datasource.symbol.exchange=NASDAQ&datasource.workspaceName=demo`.

## Plugin Options

Options are passed as comma-separated `name=value` pairs in `buf.gen.yaml`.

```yaml
plugins:
  - local: protoc-gen-connect2rest
    out: src/generated/connect2axum
    opt:
      - buffa_module=crate::proto
      - connect_module=crate::connect
  - local: protoc-gen-connect2ws
    out: src/generated/connect2axum
    opt:
      - buffa_module=crate::proto
      - connect_module=crate::connect
  - local: protoc-gen-connect2openapi
    out: src/generated/openapi
    strategy: all
    opt:
      - config=connect2openapi.yaml
  - local: protoc-gen-connect2asyncapi
    out: src/generated/asyncapi
    strategy: all
    opt:
      - config=connect2asyncapi.yaml
```

### Active Options

| Option | Default | Used By | Purpose |
| --- | --- | --- | --- |
| `buffa_module` | `crate::proto` | REST, WS | Rust module root where Buffa generated messages are available. |
| `connect_module` | `crate::connect` | REST, WS | Rust module root where Connect Rust generated service traits are available. |
| `runtime_module` | `::connect2axum` | REST, WS | Rust path to the runtime helper crate/module. |
| `streaming_content_type` | `application/x-ndjson` | REST | REST streaming response content type. |
| `suppress_pkg_prefix` | `true` | OpenAPI, AsyncAPI | Omit protobuf package prefixes from document component names and references. |
| `value_suffix` | `__` | REST, WS | Suffix for generated local bindings to avoid collisions with request fields. |
| `type_suffix` | `__` | REST | Suffix for generated DTO type names. |
| `body_message_suffix` | `Body` | REST | Suffix for generated body DTOs. |
| `query_message_suffix` | `Query` | REST | Suffix for generated query DTOs. |

### OpenAPI Generator

`protoc-gen-connect2openapi` wraps grpc-gateway's
`protoc-gen-openapiv3`, then patches the generated document for connect2axum
REST behavior. It supports `output`, `config`, `openapiv3_bin`,
`openapiv3_opt`, `streaming_content_type`, and `suppress_pkg_prefix` plugin
options.

See [docs/openapi-generator.md](docs/openapi-generator.md) for config format
and backend details.

### AsyncAPI Generator

`protoc-gen-connect2asyncapi` emits AsyncAPI v3.1 JSON for the JSON WebSocket
routes generated by `protoc-gen-connect2ws`. It supports `output`, `config`,
`server_url`, `default_content_type`, and `suppress_pkg_prefix` plugin options.

See [docs/asyncapi-generator.md](docs/asyncapi-generator.md) for document shape
and config details.

### WebSocket Notes

`protoc-gen-connect2ws` only generates JSON WebSocket routes for streaming RPCs.
Unary RPCs stay REST/Connect-only. Client and bidirectional request streams end
with an empty text frame so the socket can remain open for any response frames.