# bytes型フィールドのbase64シリアライズ対応
## 問題
OpenAPI `{ type: string, format: byte }` はJSON上でbase64エンコード文字列として送受信される。
現在の生成コードは `Vec<u8>` にマップするが、serdeのデフォルトは数値配列を期待するため不一致が生じる。
```
Error: invalid type: string, expected a sequence
```
## 解決方針
**`base64` クレートを使ったインライン serde ヘルパー** を生成コードに埋め込む。
- `serde_with` より軽量(proc-macro不要)
- 生成ファイルが自己完結する
- required / optional 両方に対応
## 採用方針
外部依存ゼロの独自実装。`base64_serde` モジュールを `UTILITY()` マクロに埋め込む。
- encode/decode 各4行、serde ラッパー含め約20行
- `serde_with` 不要、`base64` クレート不要
- `serde` のみで完結(すでに必須依存)
## 変更箇所
### 1. UTILITY() に base64_serde モジュールを追加(実装済み)
```rust
mod base64_serde {
fn enc(b: &[u8]) -> String { /* RFC4648 standard, 4行 */ }
fn dec(s: &str) -> Result<Vec<u8>, String> { /* 4行 */ }
pub fn serialize<S:Serializer>(b: &Vec<u8>, s: S) -> ...
pub fn deserialize<'de,D:Deserializer<'de>>(d: D) -> Result<Vec<u8>,D::Error>
pub mod opt {
// Option<Vec<u8>> 用
pub fn serialize / pub fn deserialize
}
}
```
### 2. IDENTIFIED_SCHEMA フィールド生成に #[serde(with)] を追加(実装済み)
```
{%- if property.type == "string" and property.format == "byte" %}
{%- if schema.required and property_key in schema.required %}
#[serde(with = "base64_serde")]
{%- else %}
#[serde(default, with = "base64_serde::opt")]
{%- endif %}
{%- endif %}
```
## 生成されるコードイメージ
```rust
#[derive(Default, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct JobRequest {
#[serde(with = "base64_serde")]
pub archive: Vec<u8>, // required: format: byte
#[serde(default, with = "base64_serde::opt")]
pub thumbnail: Option<Vec<u8>>, // optional: format: byte
pub name: String,
}
```
## ユーザー側の変更
なし。追加依存不要。
## 影響範囲
- `SCHEMA` マクロの型出力は変更しない(`Vec<u8>` のまま)
- `#[serde(...)]` アトリビュートの追加のみ
- requestBody の bytes(octet-stream等)は対象外