Skip to content

OpenAPI drift: 16 gaps between live spec and library #224

@github-actions

Description

@github-actions

The live ClickHouse Cloud OpenAPI spec has operations or schemas that the
Rust library (client.rs / models.rs) does not cover yet.

  • Live spec: https://api.clickhouse.cloud/v1
  • Client: crates/clickhouse-cloud-api/src/client.rs
  • Models: crates/clickhouse-cloud-api/src/models.rs
  • Beta metadata: crates/clickhouse-cloud-api/src/meta.rs

Summary

Change Count
Missing client methods 2
Extra client methods (not in spec) 0
Missing model types 4
Missing struct fields 2
Field optionality mismatches 0
Beta status changes 2
Stale snapshot changes 6

Missing Client Methods

The live spec has these operations but client.rs has no matching pub async fn.

slow_query_pattern_get

GET /v1/organizations/{organizationId}/postgres/{postgresId}/slowQueryPatterns/{queryId}

Get a Postgres slow query pattern with recent executions

References missing types: PostgresSlowQueryPatternDetail

Operation spec JSON
{
  "summary": "Get a Postgres slow query pattern with recent executions",
  "description": "**This endpoint is in beta.** API contract is stable, and no breaking changes are expected in the future. <br /><br /> Returns aggregate metrics for a single slow query pattern together with its most recent individual executions.",
  "operationId": "slowQueryPatternGet",
  "parameters": [
    {
      "in": "path",
      "name": "organizationId",
      "description": "ID of the organization that owns the Postgres service.",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    },
    {
      "in": "path",
      "name": "postgresId",
      "description": "ID of the requested Postgres service.",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    },
    {
      "in": "path",
      "name": "queryId",
      "description": "Stable identifier for the query pattern.",
      "required": true,
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "db_name",
      "description": "Database name filter.",
      "schema": {
        "type": "string"
      },
      "required": true
    },
    {
      "in": "query",
      "name": "db_user",
      "description": "Database user filter.",
      "schema": {
        "type": "string"
      },
      "required": true
    },
    {
      "in": "query",
      "name": "db_operation",
      "description": "Database operation filter (for example, SELECT, INSERT, UPDATE, DELETE, UTILITY).",
      "schema": {
        "type": "string"
      },
      "required": true
    },
    {
      "in": "query",
      "name": "app",
      "description": "Application name filter.",
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "timestamp",
      "description": "Timestamp of a specific execution (RFC 3339).",
      "schema": {
        "type": "string",
        "format": "date-time"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Successful response",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "number",
                "description": "HTTP status code.",
                "example": 200
              },
              "requestId": {
                "type": "string",
                "description": "Unique id assigned to every request. UUIDv4",
                "format": "uuid"
              },
              "result": {
                "$ref": "#/components/schemas/PostgresSlowQueryPatternDetail"
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "The request cannot be processed due to a client error. Please verify your request parameters and try again.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "number",
                "description": "HTTP status code.",
                "example": 400
              },
              "error": {
                "type": "string",
                "description": "Detailed error description."
              },
              "requestId": {
                "type": "string",
                "description": "Unique id assigned to every request. UUIDv4",
                "format": "uuid"
              }
            }
          }
        }
      }
    },
    "500": {
      "description": "An internal server error has occurred. If this issue persists, please contact ClickHouse Cloud support for assistance.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "integer",
                "description": "HTTP status code.",
                "example": 500
              },
              "error": {
                "type": "string",
                "description": "Detailed error description."
              },
              "requestId": {
                "type": "string",
                "description": "Unique id assigned to every request. UUIDv4",
                "format": "uuid"
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    "Postgres"
  ],
  "x-badges": [
    {
      "name": "Beta",
      "position": "after"
    }
  ]
}

slow_query_patterns_get_list

GET /v1/organizations/{organizationId}/postgres/{postgresId}/slowQueryPatterns

List Postgres slow query patterns

References missing types: PostgresSlowQueryPattern

Operation spec JSON
{
  "summary": "List Postgres slow query patterns",
  "description": "**This endpoint is in beta.** API contract is stable, and no breaking changes are expected in the future. <br /><br /> Returns aggregate metrics for the slowest query patterns observed on a Postgres service during the given time window. Use this to discover which queries dominate total execution time, CPU, I/O, or WAL generation.",
  "operationId": "slowQueryPatternsGetList",
  "parameters": [
    {
      "in": "path",
      "name": "organizationId",
      "description": "ID of the organization that owns the Postgres service.",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    },
    {
      "in": "path",
      "name": "postgresId",
      "description": "ID of the requested Postgres service.",
      "required": true,
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    },
    {
      "in": "query",
      "name": "from_date",
      "description": "Inclusive start of the time window (RFC 3339 date-time).",
      "schema": {
        "type": "string",
        "format": "date-time"
      },
      "required": true
    },
    {
      "in": "query",
      "name": "to_date",
      "description": "Exclusive end of the time window (RFC 3339 date-time).",
      "schema": {
        "type": "string",
        "format": "date-time"
      },
      "required": true
    },
    {
      "in": "query",
      "name": "db_name",
      "description": "Database name filter.",
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "db_user",
      "description": "Database user filter.",
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "db_operation",
      "description": "Database operation filter (for example, SELECT, INSERT, UPDATE, DELETE, UTILITY).",
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "app",
      "description": "Application name filter.",
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "sort_by",
      "description": "Field to sort results by.",
      "schema": {
        "type": "string",
        "enum": [
          "total_duration",
          "avg_duration",
          "call_count",
          "total_blks_read",
          "total_cpu_time",
          "error_count",
          "max_duration",
          "p50_duration",
          "p95_duration",
          "p99_duration",
          "total_rows",
          "total_shared_blks_hit",
          "total_wal_bytes"
        ],
        "default": "total_duration"
      }
    },
    {
      "in": "query",
      "name": "sort_order",
      "description": "Sort order. One of `asc` or `desc`.",
      "schema": {
        "type": "string",
        "enum": [
          "asc",
          "desc"
        ],
        "default": "desc"
      }
    },
    {
      "in": "query",
      "name": "limit",
      "description": "Maximum number of results to return.",
      "schema": {
        "type": "integer",
        "minimum": 1,
        "maximum": 500,
        "default": 20
      }
    },
    {
      "in": "query",
      "name": "offset",
      "description": "Number of results to skip before returning.",
      "schema": {
        "type": "integer",
        "minimum": 0,
        "default": 0
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Successful response",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "number",
                "description": "HTTP status code.",
                "example": 200
              },
              "requestId": {
                "type": "string",
                "description": "Unique id assigned to every request. UUIDv4",
                "format": "uuid"
              },
              "result": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PostgresSlowQueryPattern"
                }
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "The request cannot be processed due to a client error. Please verify your request parameters and try again.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "number",
                "description": "HTTP status code.",
                "example": 400
              },
              "error": {
                "type": "string",
                "description": "Detailed error description."
              },
              "requestId": {
                "type": "string",
                "description": "Unique id assigned to every request. UUIDv4",
                "format": "uuid"
              }
            }
          }
        }
      }
    },
    "500": {
      "description": "An internal server error has occurred. If this issue persists, please contact ClickHouse Cloud support for assistance.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "integer",
                "description": "HTTP status code.",
                "example": 500
              },
              "error": {
                "type": "string",
                "description": "Detailed error description."
              },
              "requestId": {
                "type": "string",
                "description": "Unique id assigned to every request. UUIDv4",
                "format": "uuid"
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    "Postgres"
  ],
  "x-badges": [
    {
      "name": "Beta",
      "position": "after"
    }
  ]
}

Missing Model Types

The live spec defines these schemas but models.rs has no matching
pub struct, pub enum, or pub type.

CustomPrivateDnsMapping (spec name: CustomPrivateDnsMapping)

Schema JSON
{
  "properties": {
    "privateDnsName": {
      "description": "Optional private DNS names for Reverse Private Endpoint. Can be used as data source destination address. Must be unique across the ClickHouse service.\nCurrently, available in Private Preview for Google Private Service Connect (PSC) forwarding rules.\nSupports exact names and leading wildcard names such as *.example.com",
      "type": "string",
      "example": "*.my-service.example.com"
    }
  }
}

PostgresQueryExecution (spec name: PostgresQueryExecution)

Schema JSON
{
  "properties": {
    "timestamp": {
      "description": "Execution timestamp (RFC 3339).",
      "type": "string",
      "format": "date-time"
    },
    "queryId": {
      "description": "Stable identifier for the query pattern.",
      "type": "string"
    },
    "dbName": {
      "description": "Database the query ran in.",
      "type": "string"
    },
    "dbUser": {
      "description": "Database user that executed the query.",
      "type": "string"
    },
    "dbOperation": {
      "description": "Top-level SQL operation type.",
      "type": "string"
    },
    "app": {
      "description": "Value of the Postgres `application_name` for this execution.",
      "type": "string"
    },
    "queryText": {
      "description": "Normalized query text for this execution.",
      "type": "string"
    },
    "pid": {
      "description": "Postgres backend process ID that executed the query.",
      "type": "string"
    },
    "durationUs": {
      "description": "Execution duration in microseconds.",
      "type": "integer"
    },
    "rows": {
      "description": "Rows returned or affected.",
      "type": "integer"
    },
    "sharedBlksHit": {
      "description": "Shared buffer blocks hit.",
      "type": "integer"
    },
    "sharedBlksRead": {
      "description": "Shared buffer blocks read from disk.",
      "type": "integer"
    },
    "sharedBlksWritten": {
      "description": "Shared buffer blocks written.",
      "type": "integer"
    },
    "sharedBlksDirtied": {
      "description": "Shared buffer blocks dirtied.",
      "type": "integer"
    },
    "sharedBlkReadTimeUs": {
      "description": "Time spent reading shared blocks, in microseconds.",
      "type": "integer"
    },
    "sharedBlkWriteTimeUs": {
      "description": "Time spent writing shared blocks, in microseconds.",
      "type": "integer"
    },
    "localBlksHit": {
      "description": "Local buffer blocks hit (temp tables).",
      "type": "integer"
    },
    "localBlksRead": {
      "description": "Local buffer blocks read (temp tables).",
      "type": "integer"
    },
    "localBlksWritten": {
      "description": "Local buffer blocks written (temp tables).",
      "type": "integer"
    },
    "localBlksDirtied": {
      "description": "Local buffer blocks dirtied (temp tables).",
      "type": "integer"
    },
    "tempBlksRead": {
      "description": "Temp blocks read (spills to disk).",
      "type": "integer"
    },
    "tempBlksWritten": {
      "description": "Temp blocks written (spills to disk).",
      "type": "integer"
    },
    "tempBlkReadTimeUs": {
      "description": "Time spent reading temp blocks, in microseconds.",
      "type": "integer"
    },
    "tempBlkWriteTimeUs": {
      "description": "Time spent writing temp blocks, in microseconds.",
      "type": "integer"
    },
    "walRecords": {
      "description": "Number of WAL records produced.",
      "type": "integer"
    },
    "walBytes": {
      "description": "Number of WAL bytes produced.",
      "type": "integer"
    },
    "walFpi": {
      "description": "Number of WAL full-page images produced.",
      "type": "integer"
    },
    "cpuUserTimeUs": {
      "description": "CPU time spent in user mode, in microseconds.",
      "type": "integer"
    },
    "cpuSysTimeUs": {
      "description": "CPU time spent in kernel mode, in microseconds.",
      "type": "integer"
    },
    "jitFunctions": {
      "description": "Number of JIT-compiled functions.",
      "type": "integer"
    },
    "jitGenerationTimeUs": {
      "description": "JIT generation time, in microseconds.",
      "type": "integer"
    },
    "jitInliningTimeUs": {
      "description": "JIT inlining time, in microseconds.",
      "type": "integer"
    },
    "jitOptimizationTimeUs": {
      "description": "JIT optimization time, in microseconds.",
      "type": "integer"
    },
    "jitEmissionTimeUs": {
      "description": "JIT emission time, in microseconds.",
      "type": "integer"
    },
    "jitDeformTimeUs": {
      "description": "JIT deform time, in microseconds.",
      "type": "integer"
    },
    "parallelWorkersPlanned": {
      "description": "Parallel workers planned for this execution.",
      "type": "integer"
    },
    "parallelWorkersLaunched": {
      "description": "Parallel workers actually launched for this execution.",
      "type": "integer"
    },
    "errMessage": {
      "description": "Error message if the execution raised an error.",
      "type": "string"
    },
    "errSqlstate": {
      "description": "Postgres SQLSTATE code if the execution raised an error.",
      "type": "string"
    },
    "errElevel": {
      "description": "Postgres error severity level if the execution raised an error.",
      "type": "integer"
    },
    "serverRole": {
      "description": "Role of the server that executed the query (for example, primary or standby).",
      "type": "string"
    },
    "traceId": {
      "description": "OpenTelemetry trace ID associated with the execution.",
      "type": "string"
    },
    "spanId": {
      "description": "OpenTelemetry span ID associated with the execution.",
      "type": "string"
    }
  },
  "required": [
    "timestamp",
    "queryId",
    "dbName",
    "dbUser",
    "dbOperation",
    "app",
    "queryText",
    "pid",
    "durationUs",
    "rows",
    "sharedBlksHit",
    "sharedBlksRead",
    "sharedBlksWritten",
    "sharedBlksDirtied",
    "sharedBlkReadTimeUs",
    "sharedBlkWriteTimeUs",
    "localBlksHit",
    "localBlksRead",
    "localBlksWritten",
    "localBlksDirtied",
    "tempBlksRead",
    "tempBlksWritten",
    "tempBlkReadTimeUs",
    "tempBlkWriteTimeUs",
    "walRecords",
    "walBytes",
    "walFpi",
    "cpuUserTimeUs",
    "cpuSysTimeUs",
    "jitFunctions",
    "jitGenerationTimeUs",
    "jitInliningTimeUs",
    "jitOptimizationTimeUs",
    "jitEmissionTimeUs",
    "jitDeformTimeUs",
    "parallelWorkersPlanned",
    "parallelWorkersLaunched",
    "serverRole"
  ]
}

PostgresSlowQueryPattern (spec name: PostgresSlowQueryPattern)

Schema JSON
{
  "properties": {
    "queryId": {
      "description": "Stable identifier for the query pattern (normalized SQL).",
      "type": "string"
    },
    "queryText": {
      "description": "Normalized query text with literals replaced by placeholders.",
      "type": "string"
    },
    "dbName": {
      "description": "Database the query ran in.",
      "type": "string"
    },
    "dbUser": {
      "description": "Database user that executed the query.",
      "type": "string"
    },
    "dbOperation": {
      "description": "Top-level SQL operation type (for example, SELECT, INSERT, UPDATE, DELETE, UTILITY).",
      "type": "string"
    },
    "app": {
      "description": "Value of the Postgres `application_name` for executions matching this pattern.",
      "type": "string"
    },
    "callCount": {
      "description": "Number of times the pattern executed in the window.",
      "type": "integer"
    },
    "errorCount": {
      "description": "Number of executions of the pattern that raised an error.",
      "type": "integer"
    },
    "totalDurationUs": {
      "description": "Total execution time across all calls, in microseconds.",
      "type": "integer"
    },
    "avgDurationUs": {
      "description": "Average execution time per call, in microseconds.",
      "type": "integer"
    },
    "maxDurationUs": {
      "description": "Maximum execution time of any call, in microseconds.",
      "type": "integer"
    },
    "p50DurationUs": {
      "description": "50th percentile execution time, in microseconds.",
      "type": "integer"
    },
    "p95DurationUs": {
      "description": "95th percentile execution time, in microseconds.",
      "type": "integer"
    },
    "p99DurationUs": {
      "description": "99th percentile execution time, in microseconds.",
      "type": "integer"
    },
    "totalRows": {
      "description": "Total number of rows returned or affected across all calls.",
      "type": "integer"
    },
    "totalSharedBlksRead": {
      "description": "Total shared buffer blocks read from disk (cache misses) across all calls.",
      "type": "integer"
    },
    "totalSharedBlksHit": {
      "description": "Total shared buffer blocks hit (cache hits) across all calls.",
      "type": "integer"
    },
    "totalCpuTimeUs": {
      "description": "Total CPU time across all calls, in microseconds.",
      "type": "integer"
    },
    "totalWalBytes": {
      "description": "Total WAL (write-ahead log) bytes generated across all calls.",
      "type": "integer"
    }
  },
  "required": [
    "queryId",
    "queryText",
    "dbName",
    "dbUser",
    "dbOperation",
    "app",
    "callCount",
    "errorCount",
    "totalDurationUs",
    "avgDurationUs",
    "maxDurationUs",
    "p50DurationUs",
    "p95DurationUs",
    "p99DurationUs",
    "totalRows",
    "totalSharedBlksRead",
    "totalSharedBlksHit",
    "totalCpuTimeUs",
    "totalWalBytes"
  ]
}

PostgresSlowQueryPatternDetail (spec name: PostgresSlowQueryPatternDetail)

Schema JSON
{
  "properties": {
    "aggregate": {
      "$ref": "#/components/schemas/PostgresSlowQueryPattern"
    },
    "recentExecutions": {
      "type": "array",
      "description": "Recent individual executions matching the pattern.",
      "items": {
        "$ref": "#/components/schemas/PostgresQueryExecution"
      }
    }
  },
  "required": [
    "recentExecutions"
  ]
}

Missing Struct Fields

These properties exist in the OpenAPI spec but have no corresponding
field in the Rust struct. API response data for these fields is silently
dropped during deserialization.

Schema Field
CreateReversePrivateEndpoint customPrivateDnsMappings
ReversePrivateEndpoint customPrivateDnsMappings

Beta Status Changes

The live spec's x-badges Beta markers have drifted from
BETA_OPERATIONS in crates/clickhouse-cloud-api/src/meta.rs.
Consumers of the typed client (including this CLI) read that constant
to render (Beta) affordances and gate stability-sensitive code paths.

Newly Beta in live spec (add to BETA_OPERATIONS):

  • slow_query_pattern_get
  • slow_query_patterns_get_list

Regenerate the list with:

python3 scripts/regenerate-beta-lists.py

Stale Snapshot

The committed clickhouse_cloud_openapi.json is behind the live spec.
Tests that run against the snapshot may pass even though the library is
missing coverage for new endpoints or schemas.

New operations in live spec (not in snapshot):

  • slow_query_pattern_get
  • slow_query_patterns_get_list

New schemas in live spec (not in snapshot):

  • CustomPrivateDnsMapping
  • PostgresQueryExecution
  • PostgresSlowQueryPattern
  • PostgresSlowQueryPatternDetail

Implementation Guide

  1. Update the checked-in spec:
    curl -s https://api.clickhouse.cloud/v1 -o crates/clickhouse-cloud-api/clickhouse_cloud_openapi.json
  2. Add missing types to crates/clickhouse-cloud-api/src/models.rs
    • Use #[serde(rename_all = "camelCase")] on structs
    • Use #[serde(skip_serializing_if = "Option::is_none")] for optional fields
    • Enums should derive Default and include an #[serde(other)] Unknown variant
  3. Add missing methods to crates/clickhouse-cloud-api/src/client.rs
  4. Fix any field optionality mismatches by hand-editing models.rs
    (flip TOption<T> and the matching skip_serializing_if attribute).
  5. Verify: cargo test -p clickhouse-cloud-api

Metadata

Metadata

Assignees

Labels

openapi-driftAutomated: live OpenAPI spec has operations/schemas not covered by the Rust library

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions