# Protobuf data format

> The `protobuf` data format encodes the message body as Protocol Buffers bytes (or proto3 JSON) using a `.proto` file, and decodes protobuf data back into a structured body.

**Name:** `protobuf` · **Crate:** `cameleer-grpc` · **Cargo feature:** [`grpc`](../guides/build-features.md) ·
**Apache Camel:** [Protobuf](https://camel.apache.org/components/next/dataformats/protobuf-dataformat.html)

## When to use it

- Exchange protobuf messages over Kafka, MQTT or HTTP with services generated by `protoc`.
- Decode device telemetry sent as protobuf from edge hardware.
- Convert between protobuf and JSON at an API gateway.

For gRPC calls, the [grpc component](../components/grpc.md) uses the same `.proto` support.

## Marshal and unmarshal

| direction | body in | body out |
|---|---|---|
| `marshal`, `contentTypeFormat: native` (default) | an object, JSON text, or bytes that are already encoded | protobuf bytes. Sets `Content-Type: application/octet-stream`. |
| `marshal`, `contentTypeFormat: json` | an object, JSON text or protobuf bytes | proto3 JSON text (lowerCamelCase names). Sets `Content-Type: application/json`. |
| `unmarshal`, `native` | protobuf bytes | an object keyed by field name |
| `unmarshal`, `json` | proto3 JSON text | an object |

The `.proto` file is parsed at runtime: proto3 and basic proto2, imports from the same directory,
nested types, enums, `repeated` (packed), `map`, `oneof` and the well-known types.

**Difference from Apache Camel:** no generated Java classes. `instanceClass` names the protobuf
message (`edge.Reading`; a Java name such as `org.acme.Outer$Reading` is reduced to `Reading`), and
`protoFile` points at the `.proto` file.

## Example

The message type used by the examples:

<!-- file: reading.proto -->
```text
syntax = "proto3";
package edge;

message Reading {
  string id = 1;
  double temp = 2;
  bool ok = 3;
}
```

Encode a JSON reading as protobuf and show the 16 bytes:

<!-- example: protobuf-encode -->
```yaml
- route:
    id: protobuf-encode
    from:
      uri: direct:protobuf-encode
      steps:
        - marshal:
            protobuf:
              instanceClass: edge.Reading
              protoFile: reading.proto
        - marshal:
            hex: {}
```

<!-- input: protobuf-encode -->
```json
{"id":"s-1","temp":21.5,"ok":true}
```

<!-- output: protobuf-encode -->
```text
0a03732d311100000000008035401801
```

Decode protobuf bytes and read a field:

<!-- example: protobuf-decode -->
```yaml
- route:
    id: protobuf-decode
    from:
      uri: direct:protobuf-decode
      steps:
        - unmarshal:
            hex: {}
        - unmarshal:
            protobuf:
              instanceClass: edge.Reading
              protoFile: reading.proto
        - setBody:
            simple: "${body.id} reports ${body.temp}"
```

<!-- input: protobuf-decode -->
```text
0a03732d311100000000008035401801
```

<!-- output: protobuf-decode -->
```text
s-1 reports 21.5
```

## Rust DSL

```rust
b.from("direct:protobuf-rust")
    .marshal(
        DataFormatDefinition::new("protobuf")
            .option("instanceClass", "edge.Reading")
            .option("protoFile", "reading.proto"),
    );
```

`cameleer_grpc::protobuf("reading.proto", "edge.Reading")?` builds the same definition and fails
early if the file does not parse.

## Options

| option | default | description |
|---|---|---|
| `instanceClass` | (none) | The protobuf message name, e.g. `edge.Reading`. Required with `protoFile`. |
| `protoFile` | (none) | Path of the `.proto` file. |
| `contentTypeFormat` | `native` | `native` (binary) or `json` (proto3 JSON). |
| `contentTypeHeader` | `true` | Set the `Content-Type` header on marshal. |

Without `instanceClass` and `protoFile`, the format is configured per message by the headers
`CamelProtobufInstanceClass`, `CamelProtobufProtoFile` and `CamelProtobufContentTypeFormat`, or the
properties `camel.dataformat.protobuf.instanceClass`, `.protoFile` and `.contentTypeFormat`.

## Common questions

### Do I need to run protoc?

No. The `.proto` file is read at runtime; there is no code generation step.

### How do I convert protobuf to JSON?

`unmarshal` with the native format, then `marshal: {json: {}}`; or `marshal` with
`contentTypeFormat: json`, which writes proto3 JSON (lowerCamelCase names, enums as names).

## Related

- [grpc component](../components/grpc.md)
- [Avro data format](avro.md), [Thrift data format](thrift.md), [CBOR data format](cbor.md)
- [Apache Camel Protobuf data format](https://camel.apache.org/components/next/dataformats/protobuf-dataformat.html)

## Found a problem?

If something on this page doesn't match what Cameleer does, or you hit a bug while building
with it, please help fix it, whether you are a person or a coding agent:
[open an issue](https://github.com/pmsudhi/cameleer/issues/new) that describes what you saw,
then fork the repository, fix it, add or update a test, run `cargo test --workspace`, and open
a pull request. [CONTRIBUTING.md](https://github.com/pmsudhi/cameleer/blob/main/CONTRIBUTING.md)
explains the ground rules.
