Bug Report Checklist
Description
rust-axum does not honor OpenAPI integer formats uint32 and uint64.
When a schema property is declared as:
type: integer
format: uint32 or format: uint64
the generated Rust code still uses signed i32 for model fields and also uses <i32 as std::str::FromStr> in generated query parsing code.
This causes incorrect Rust types in generated server models and can also lead to type mismatches in generated parsing code.
I found a related issue, but it appears to be different in scope:
openapi-generator version
7.21.0
OpenAPI declaration file content or url
openapi: 3.0.3
info:
title: Rust Axum Integer Type Mapping Test
version: 1.0.0
paths:
/integers:
get:
parameters:
- name: legacy_uint32
in: query
required: true
schema:
type: integer
format: uint32
- name: legacy_uint64
in: query
required: true
schema:
type: integer
format: uint64
Generation Details
openapi-generator generate -g rust-axum -I repro.yaml -o out
Steps to reproduce
- Save the spec above as repro.yaml
- Run the openapi-generator generate command above
- Inspect out/src/models.rs
- Actual output
pub count32: i32,
pub count64: i32,
- Expected output
pub count32: u32,
pub count64: u64,
Related issues/PRs
Suggest a fix
- Override
getSchemaType in RustAxumServerCodegen and handle integer schemas explicitly.
- Treat legacy
format: uint32 and format: uint64 as u32 and u64 for backward compatibility.
- For standard OpenAPI integer formats:
type: integer, format: int32, minimum >= 0 -> u32
type: integer, format: int64, minimum >= 0 -> u64
- If
x-unsigned: true is present, map int32/int64 to unsigned Rust types as well.
- If no format is provided, reuse the existing best-fit integer selection logic based on
minimum/maximum.
- Apply the same logic consistently for:
- model properties
- parameter types
- array/map inner integer types
I also drafted a patch for the fix:
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java
index a6450d6f3f..d85b30c891 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java
@@ -44,6 +44,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
+import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.file.Path;
import java.util.*;
@@ -1024,6 +1025,62 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege
return codegenParameter;
}
+ private String getIntegerDataType(String format,
+ BigInteger minimum,
+ boolean exclusiveMinimum,
+ BigInteger maximum,
+ boolean exclusiveMaximum,
+ boolean explicitUnsigned) {
+ boolean unsigned = explicitUnsigned || canFitIntoUnsigned(minimum, exclusiveMinimum);
+
+ if (StringUtils.isEmpty(format)) {
+ return bestFittingIntegerType(
+ minimum,
+ exclusiveMinimum,
+ maximum,
+ exclusiveMaximum,
+ true);
+ }
+
+ switch (format) {
+ case "uint32":
+ return "u32";
+ case "uint64":
+ return "u64";
+ case "int32":
+ return unsigned ? "u32" : "i32";
+ case "int64":
+ return unsigned ? "u64" : "i64";
+ default:
+ LOGGER.warn("The integer format '{}' is not recognized and will be ignored.", format);
+ return bestFittingIntegerType(
+ minimum,
+ exclusiveMinimum,
+ maximum,
+ exclusiveMaximum,
+ true);
+ }
+ }
+
+ @Override
+ public String getSchemaType(Schema p) {
+ if (Objects.equals(p.getType(), "integer")) {
+ BigInteger minimum = Optional.ofNullable(p.getMinimum()).map(BigDecimal::toBigInteger).orElse(null);
+ BigInteger maximum = Optional.ofNullable(p.getMaximum()).map(BigDecimal::toBigInteger).orElse(null);
+ boolean explicitUnsigned = ModelUtils.isUnsignedIntegerSchema(p) || ModelUtils.isUnsignedLongSchema(p);
+
+ return getIntegerDataType(
+ p.getFormat(),
+ minimum,
+ Optional.ofNullable(p.getExclusiveMinimum()).orElse(false),
+ maximum,
+ Optional.ofNullable(p.getExclusiveMaximum()).orElse(false),
+ explicitUnsigned);
+ }
+
+ return super.getSchemaType(p);
+ }
+
@Override
public String toInstantiationType(final Schema p) {
if (ModelUtils.isArraySchema(p)) {
@@ -1113,13 +1170,17 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege
}
// Integer type fitting
- if (Objects.equals(property.baseType, "integer")) {
+ if (Boolean.TRUE.equals(property.isInteger) || Boolean.TRUE.equals(property.isLong) || Objects.equals(property.baseType, "UnsignedInteger") || Objects.equals(property.baseType, "UnsignedLong")) {
BigInteger minimum = Optional.ofNullable(property.getMinimum()).map(BigInteger::new).orElse(null);
BigInteger maximum = Optional.ofNullable(property.getMaximum()).map(BigInteger::new).orElse(null);
- property.dataType = bestFittingIntegerType(
- minimum, property.getExclusiveMinimum(),
- maximum, property.getExclusiveMaximum(),
- true);
+ boolean explicitUnsigned = Objects.equals(property.baseType, "UnsignedInteger") || Objects.equals(property.baseType, "UnsignedLong");
+ property.dataType = getIntegerDataType(
+ property.dataFormat,
+ minimum,
+ property.getExclusiveMinimum(),
+ maximum,
+ property.getExclusiveMaximum(),
+ explicitUnsigned);
}
property.name = underscore(property.name);
Bug Report Checklist
Description
rust-axumdoes not honor OpenAPI integer formatsuint32anduint64.When a schema property is declared as:
type: integerformat: uint32orformat: uint64the generated Rust code still uses signed
i32for model fields and also uses<i32 as std::str::FromStr>in generated query parsing code.This causes incorrect Rust types in generated server models and can also lead to type mismatches in generated parsing code.
I found a related issue, but it appears to be different in scope:
uint32/uint64type mapping itself.openapi-generator version
7.21.0
OpenAPI declaration file content or url
Generation Details
Steps to reproduce
Related issues/PRs
uint32/uint64Rust type mapping)Suggest a fix
getSchemaTypeinRustAxumServerCodegenand handle integer schemas explicitly.format: uint32andformat: uint64asu32andu64for backward compatibility.type: integer, format: int32, minimum >= 0->u32type: integer, format: int64, minimum >= 0->u64x-unsigned: trueis present, mapint32/int64to unsigned Rust types as well.minimum/maximum.I also drafted a patch for the fix: