Generating Iceberg REST Catalog Client
This guide explains how to regenerate the Rust client code for the Iceberg REST Catalog from the OpenAPI specification.
Prerequisites
To regenerate the REST client from the OpenAPI specification, you need to install the OpenAPI Generator CLI:
brew install openapi-generatorFor other installation methods, see the OpenAPI Generator CLI Installation Guide.
Configuration
Generator configuration is defined in crates/sail-catalog-iceberg/spec/openapi-generator-config.yaml.
Generating the REST Client
The REST client is auto-generated from the Iceberg REST Catalog OpenAPI spec.
To regenerate the client code, run the generation script from the repository root:
./crates/sail-catalog-iceberg/spec/generate-client.shOr from the spec directory:
cd crates/sail-catalog-iceberg/spec
./generate-client.shThe script will:
- Generate Rust client code from the OpenAPI spec using
--schema-mappingsto use custom types fromsrc/types/ - Extract
apis/andmodels/directories tosrc/ - Format the generated code with
cargo fmt
The generated code will be placed in src/apis/ and src/models/.
Schema Mappings
The generator uses custom type mappings to avoid problematic generated code:
Type,StructType,ListType,MapType,StructField→crate::types::{Type,StructType,ListType,MapType, NestedFieldRef}
Post-Generation Manual Steps
OpenAPI 3.1 support is still in beta when generating Rust clients with the OpenAPI Generator. After running the generation script, you must manually fix the following:
In
src/apis/catalog_api_api.rs:- Replace
"{}/v1/{prefix}/with"{}/v1{prefix}/ - Replace
crate::apis::urlencode(prefix.unwrap())withprefix.map(|p| format!("/{}", crate::apis::urlencode(p))).unwrap_or_default()
- Replace
In
src/apis/o_auth2_api_api.rs:- Replace
models::models::TokenTypewithmodels::TokenType
- Replace
In
src/models/schema.rs:- Replace
models::StructFieldwithNestedFieldRef
- Replace
In
src/models/table_update.rsandsrc/models/view_update.rs:- The upstream spec declares
TableUpdate/ViewUpdateas a bareanyOfwith no discriminator (unlikeBaseUpdate, which has one), so the generator emits a degenerate flat struct with every field of every variant marked required. Replace each generated struct with a hand-written#[serde(tag = "action")]enum (mirroringbase_update.rs), with one variant per action and with all payload fields preserved.
- The upstream spec declares
In
src/models/table_requirement.rs,src/models/view_requirement.rs,src/models/commit_view_request.rs, andsrc/models/assert_ref_snapshot_id.rs:- Ensure
TableRequirementis a hand-written#[serde(tag = "type")]enum whose variants preserve their payload fields. In particular,AssertRefSnapshotIdmust includerefand nullablesnapshot-id; if it is generated as an empty variant, Iceberg REST commits will serialize as{"type":"assert-ref-snapshot-id"}and servers will reject the request becauserefis missing. - Ensure
AssertRefSnapshotId.snapshot_idisOption<i64>so create transactions can send"snapshot-id": null, which means the ref must not already exist. - If the generator omits
ViewRequirementbecause it has only one variant, add it as a hand-written#[serde(tag = "type")]enum withAssertViewUuid { uuid }, and keepCommitViewRequest.requirementstyped asOption<Vec<ViewRequirement>>.
- Ensure
