Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions openapi/normalize_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@
this script swaps the Russian tags for those English names so the generator
emits one module per API area (``servers_api``, ``databases_api``, ...).

Nothing else is touched: request and response schemas are left exactly as
upstream published them.
3. ``response_id`` nullability. The shared ``response_id`` schema is a required
``uuid`` in the response wrappers, but the live API returns ``null`` on some
endpoints (e.g. ``GET /account/finances``). It is marked ``nullable`` so the
generated client deserializes the null to ``None`` instead of failing with
"invalid type: null, expected a formatted UUID string".

Request and response schemas are otherwise left exactly as upstream published
them.

Usage:
normalize_spec.py <input.json> <output.json>
Expand Down Expand Up @@ -130,10 +136,44 @@ def localize_tags(spec):
]


def nullable_response_id(spec):
"""Mark ``response_id`` nullable so a ``null`` from the API deserializes.

The upstream spec types ``response_id`` as a required ``uuid`` and the
response wrappers list it in ``required``, so the generator emits
``response_id: uuid::Uuid``. The live API does not honour this — some
endpoints (e.g. ``GET /account/finances``) return ``response_id: null``,
which then fails deserialization with "invalid type: null, expected a
formatted UUID string". Marking the shared schema (and any inline
occurrence) nullable yields ``Option<uuid::Uuid>``, so ``null`` maps to
``None`` instead of erroring.
"""
schemas = spec.get("components", {}).get("schemas", {})
shared = schemas.get("response_id")
if isinstance(shared, dict):
shared["nullable"] = True

def walk(node):
if isinstance(node, dict):
props = node.get("properties")
if isinstance(props, dict):
inline = props.get("response_id")
if isinstance(inline, dict) and "$ref" not in inline:
inline["nullable"] = True
for value in node.values():
walk(value)
elif isinstance(node, list):
for value in node:
walk(value)

walk(spec)


def normalize(spec):
"""Apply all normalization passes to ``spec`` in place and return it."""
fix_path_parameters(spec)
localize_tags(spec)
nullable_response_id(spec)
return spec


Expand Down
6 changes: 3 additions & 3 deletions src/models/add_balancer_to_project_200_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ pub struct AddBalancerToProject200Response {
pub resource: Box<models::ProjectResource>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl AddBalancerToProject200Response {
pub fn new(
resource: models::ProjectResource,
response_id: uuid::Uuid
response_id: Option<uuid::Uuid>
) -> AddBalancerToProject200Response {
AddBalancerToProject200Response {
resource: Box::new(resource),
Expand Down
6 changes: 3 additions & 3 deletions src/models/add_countries_to_allowed_list_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ pub struct AddCountriesToAllowedList201Response {
pub countries: Box<models::AddCountries>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl AddCountriesToAllowedList201Response {
pub fn new(
countries: models::AddCountries,
response_id: uuid::Uuid
response_id: Option<uuid::Uuid>
) -> AddCountriesToAllowedList201Response {
AddCountriesToAllowedList201Response {
countries: Box::new(countries),
Expand Down
9 changes: 6 additions & 3 deletions src/models/add_ips_to_allowed_list_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ pub struct AddIpsToAllowedList201Response {
pub ips: Box<models::AddIps>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl AddIpsToAllowedList201Response {
pub fn new(ips: models::AddIps, response_id: uuid::Uuid) -> AddIpsToAllowedList201Response {
pub fn new(
ips: models::AddIps,
response_id: Option<uuid::Uuid>
) -> AddIpsToAllowedList201Response {
AddIpsToAllowedList201Response {
ips: Box::new(ips),
response_id
Expand Down
9 changes: 6 additions & 3 deletions src/models/add_provider_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ pub struct AddProvider201Response {
pub provider: Box<models::Provider>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl AddProvider201Response {
pub fn new(provider: models::Provider, response_id: uuid::Uuid) -> AddProvider201Response {
pub fn new(
provider: models::Provider,
response_id: Option<uuid::Uuid>
) -> AddProvider201Response {
AddProvider201Response {
provider: Box::new(provider),
response_id
Expand Down
6 changes: 3 additions & 3 deletions src/models/add_resource_to_group_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ use crate::models;
pub struct AddResourceToGroup201Response {
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid,
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>,
#[serde(rename = "resource")]
pub resource: Box<models::FirewallGroupResource>
}

impl AddResourceToGroup201Response {
pub fn new(
response_id: uuid::Uuid,
response_id: Option<uuid::Uuid>,
resource: models::FirewallGroupResource
) -> AddResourceToGroup201Response {
AddResourceToGroup201Response {
Expand Down
9 changes: 6 additions & 3 deletions src/models/add_server_ip_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ pub struct AddServerIp201Response {
pub server_ip: Box<models::ServerIp>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl AddServerIp201Response {
pub fn new(server_ip: models::ServerIp, response_id: uuid::Uuid) -> AddServerIp201Response {
pub fn new(
server_ip: models::ServerIp,
response_id: Option<uuid::Uuid>
) -> AddServerIp201Response {
AddServerIp201Response {
server_ip: Box::new(server_ip),
response_id
Expand Down
6 changes: 3 additions & 3 deletions src/models/add_storage_subdomains_200_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ pub struct AddStorageSubdomains200Response {
pub meta: Box<models::Meta>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl AddStorageSubdomains200Response {
pub fn new(
subdomains: Vec<models::AddedSubdomain>,
meta: models::Meta,
response_id: uuid::Uuid
response_id: Option<uuid::Uuid>
) -> AddStorageSubdomains200Response {
AddStorageSubdomains200Response {
subdomains,
Expand Down
9 changes: 6 additions & 3 deletions src/models/add_subdomain_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ pub struct AddSubdomain201Response {
pub subdomain: Box<models::Subdomain>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl AddSubdomain201Response {
pub fn new(subdomain: models::Subdomain, response_id: uuid::Uuid) -> AddSubdomain201Response {
pub fn new(
subdomain: models::Subdomain,
response_id: Option<uuid::Uuid>
) -> AddSubdomain201Response {
AddSubdomain201Response {
subdomain: Box::new(subdomain),
response_id
Expand Down
9 changes: 7 additions & 2 deletions src/models/addons_config_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ use crate::models;
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct AddonsConfigResponse {
/// ID запроса
#[serde(rename = "response_id", skip_serializing_if = "Option::is_none")]
pub response_id: Option<String>,
#[serde(
rename = "response_id",
default,
with = "::serde_with::rust::double_option",
skip_serializing_if = "Option::is_none"
)]
pub response_id: Option<Option<String>>,
/// Вспомогательная информация о возвращаемой сущности
#[serde(rename = "meta")]
pub meta: Box<models::SchemasMeta>,
Expand Down
9 changes: 7 additions & 2 deletions src/models/addons_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ use crate::models;
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct AddonsResponse {
/// ID запроса
#[serde(rename = "response_id", skip_serializing_if = "Option::is_none")]
pub response_id: Option<String>,
#[serde(
rename = "response_id",
default,
with = "::serde_with::rust::double_option",
skip_serializing_if = "Option::is_none"
)]
pub response_id: Option<Option<String>>,
/// Вспомогательная информация о возвращаемой сущности
#[serde(rename = "meta")]
pub meta: Box<models::SchemasMeta>,
Expand Down
9 changes: 7 additions & 2 deletions src/models/base_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ pub struct BaseError {
pub error_code: String,
#[serde(rename = "message")]
pub message: Box<models::BaseErrorMessage>,
#[serde(rename = "response_id", skip_serializing_if = "Option::is_none")]
pub response_id: Option<String>
#[serde(
rename = "response_id",
default,
with = "::serde_with::rust::double_option",
skip_serializing_if = "Option::is_none"
)]
pub response_id: Option<Option<String>>
}

impl BaseError {
Expand Down
9 changes: 6 additions & 3 deletions src/models/check_domain_200_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ pub struct CheckDomain200Response {
pub is_domain_available: bool,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl CheckDomain200Response {
pub fn new(is_domain_available: bool, response_id: uuid::Uuid) -> CheckDomain200Response {
pub fn new(
is_domain_available: bool,
response_id: Option<uuid::Uuid>
) -> CheckDomain200Response {
CheckDomain200Response {
is_domain_available,
response_id
Expand Down
9 changes: 7 additions & 2 deletions src/models/cluster_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ use crate::models;
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct ClusterResponse {
/// ID запроса
#[serde(rename = "response_id", skip_serializing_if = "Option::is_none")]
pub response_id: Option<String>,
#[serde(
rename = "response_id",
default,
with = "::serde_with::rust::double_option",
skip_serializing_if = "Option::is_none"
)]
pub response_id: Option<Option<String>>,
/// Кластер
#[serde(rename = "cluster")]
pub cluster: Box<models::ClusterOut>
Expand Down
9 changes: 7 additions & 2 deletions src/models/clusters_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ use crate::models;
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct ClustersResponse {
/// ID запроса
#[serde(rename = "response_id", skip_serializing_if = "Option::is_none")]
pub response_id: Option<String>,
#[serde(
rename = "response_id",
default,
with = "::serde_with::rust::double_option",
skip_serializing_if = "Option::is_none"
)]
pub response_id: Option<Option<String>>,
/// Вспомогательная информация о возвращаемой сущности
#[serde(rename = "meta")]
pub meta: Box<models::SchemasMeta>,
Expand Down
9 changes: 7 additions & 2 deletions src/models/components_schemas_base_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ pub struct ComponentsSchemasBaseError {
pub error_code: String,
#[serde(rename = "message")]
pub message: Box<models::Message>,
#[serde(rename = "response_id", skip_serializing_if = "Option::is_none")]
pub response_id: Option<String>
#[serde(
rename = "response_id",
default,
with = "::serde_with::rust::double_option",
skip_serializing_if = "Option::is_none"
)]
pub response_id: Option<Option<String>>
}

impl ComponentsSchemasBaseError {
Expand Down
6 changes: 3 additions & 3 deletions src/models/create_agent_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ pub struct CreateAgent201Response {
pub agent: Box<models::Agent>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl CreateAgent201Response {
pub fn new(agent: models::Agent, response_id: uuid::Uuid) -> CreateAgent201Response {
pub fn new(agent: models::Agent, response_id: Option<uuid::Uuid>) -> CreateAgent201Response {
CreateAgent201Response {
agent: Box::new(agent),
response_id
Expand Down
6 changes: 3 additions & 3 deletions src/models/create_app_201_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ pub struct CreateApp201Response {
pub app: Box<models::App>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl CreateApp201Response {
pub fn new(app: models::App, response_id: uuid::Uuid) -> CreateApp201Response {
pub fn new(app: models::App, response_id: Option<uuid::Uuid>) -> CreateApp201Response {
CreateApp201Response {
app: Box::new(app),
response_id
Expand Down
9 changes: 6 additions & 3 deletions src/models/create_balancer_200_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ pub struct CreateBalancer200Response {
pub balancer: Box<models::Balancer>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl CreateBalancer200Response {
pub fn new(balancer: models::Balancer, response_id: uuid::Uuid) -> CreateBalancer200Response {
pub fn new(
balancer: models::Balancer,
response_id: Option<uuid::Uuid>
) -> CreateBalancer200Response {
CreateBalancer200Response {
balancer: Box::new(balancer),
response_id
Expand Down
9 changes: 6 additions & 3 deletions src/models/create_balancer_rule_200_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ pub struct CreateBalancerRule200Response {
pub rule: Box<models::Rule>,
/// ID запроса, который можно указывать при обращении в службу технической
/// поддержки, чтобы помочь определить проблему.
#[serde(rename = "response_id")]
pub response_id: uuid::Uuid
#[serde(rename = "response_id", deserialize_with = "Option::deserialize")]
pub response_id: Option<uuid::Uuid>
}

impl CreateBalancerRule200Response {
pub fn new(rule: models::Rule, response_id: uuid::Uuid) -> CreateBalancerRule200Response {
pub fn new(
rule: models::Rule,
response_id: Option<uuid::Uuid>
) -> CreateBalancerRule200Response {
CreateBalancerRule200Response {
rule: Box::new(rule),
response_id
Expand Down
Loading
Loading