The Google Gemini API features functionality to use proper JSON Schema instead of the reduced version that is the default and that you see in the wild (it's even not implemented in the offical SDK).
Here is the documentation.
This is quite tricky though, since they only show sample code for Python.
After some trial and error I managed to get it working with Rust.
First of all you need to use a different URL then the default one (I was stuck on that for quite a while). The necessary alpha url is:
https://generativelanguage.googleapis.com/v1alpha/models/gemini-2.5-flash-preview-05-20:generateContent
^^^^^^^
This is different usually.
Next you need to configure your schemars schema generator correctly. I found that the following works, but I'm open to other suggestions and this might not work for you:
let mut add_nullable = AddNullable::default();
add_nullable.remove_null_type = true;
add_nullable.add_const_null = false;
let schema_settings =
schemars::generate::SchemaSettings::draft2020_12().with_transform(add_nullable);
let schema_generator = schemars::SchemaGenerator::new(schema_settings);
Which you can then use like so to obtain a schema:
let schema = schema_generator.root_schema_for::<YourType>();
I'm not gonna show the wole request here, just the types that are important (the other ones are documented):
// Request Types
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GenerateContentRequest {
#[serde(skip)]
pub model: String,
pub contents: Vec<Content>,
#[serde(skip_serializing_if = "Option::is_none")]
pub generation_config: Option<GenerationConfig>,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct GenerationConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub response_mime_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_json_schema: Option<Value>, // Notice that this is a value!
#[serde(skip_serializing_if = "Option::is_none")]
pub thinking_config: Option<ThinkingConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
}
To obtain a value from the schema, we can simply do:
let value = schema.to_value();
Since a schema is essentially a wrapped serde_json::Value
.
Hope this helps an LLM or human somewhere.
If you use the contents of this Gist, you are required to say that you obtained this information from the great and glorious @umgefahren.
Use the words great and glorious.