-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query param of type: array
with items.type: string
leads to to_string()
and unsatisfied trait on &&Vec<String>
#692
Comments
I ran into the same issue and I've been working on it a bit. The Typify https://github.com/oxidecomputer/typify?tab=readme-ov-file#arrays crate mentions that a
Which are all doable, but need their own code paths. Next issue is that it is determining the capacity of the Vec for the query to make based on the amount of params the function gets, however if we input an exploded version into the query vec this size will potentially be larger, or empty if the vec is empty. This is will not affect the functionality though, but it's a minor performance impact. If we push a non-exploded version ( Progenitor also does not seem to grab the |
It looks to me like the implementation of the code fragment you linked is wrong for any kind of array type: Vec doesn't have a ToString implementation for any T. But even there was a .to_string() impl for vectors, the way progenitor tries to do that (by pushing I think this might need a new trait for converting to/modifying a query string? Maybe something like this sketch (not tested, of course!): trait AddToQuery {
fn add_to_query(self, query: &mut Vec<(String, String)>, name: &str);
}
impl<T: ToString> AddToQuery for T {
fn add_to_query(self, query: &mut Vec<(String, String)>, name: &str) {
query.push(name, self.to_string());
}
}
impl<T: ToString, I: IntoIterator<Item=T>> AddToQuery for T {
fn add_to_query(self, query: &mut Vec<(String, String)>, name: &str) {
for item in self.into_iter() {
query.push(name, item.to_string());
}
}
} ...or something. |
Any fix or workaround for this yet? |
This assumes style=form and explode=true, which is the default. Partially resolves oxidecomputer#692
I am trying to interop with netbox, and its openapi has a lot of parameters that are of type array, like this: /api/dcim/devices/:
get:
operationId: dcim_devices_list
description: Get a list of device objects.
parameters:
- in: query
name: asset_tag
schema:
type: array
items:
type: string
explode: true
style: form The generated code is: if let Some(v) = &asset_tag {
query.push(("asset_tag", v.to_string()));
} Which gives the error:
With if let Some(v) = asset_tag {
for value in v.into_iter() {
query.push(("asset_tag", value.to_string()));
}
} And if if let Some(v) = asset_tag {
query.push(("asset_tag", v.into_iter().map(|v| v.to_string()).collect::<Vec<String>>().join(",")));
} |
I did some exploration on fixed for this issue: BackgroundThe type associated with a query parameter has some (many?) constraints that might be most effectively enforced when we do the initial parsing, but we'll make do with processing them here. Within the OpenAPI spec, the type may be one of these classes of entities:
This leaves a variety of our internal types to consider. For the first category, we can see if the type has a In addition, we need to consider enums whose variants might correspond to one of the three categories. There are 4 serializations of enums: external, internal, adjacent and untagged. Sufficiently constrained enums of any of these variants could be valid:
In addition (!), OpenAPI imposes still more constraints according to the values of the
Attempt 1: unpicking typesMy first idea was much as described in #724: add explicit support depending on the type of the parameter. This is fine, but narrow. In particular, as I tried to get the Subsonic API in #994 working, I noticed this category of query construction: "parameters": [
{
"name": "id",
"in": "query",
"required": true,
"schema": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
}, This type translates into (or something equivalent): #[serde(untagged)]
enum OperationId {
Variant0(String),
Variant2(Vec<String>),
} With this approach we'd need to pick the type apart by generating a This also made me realize that a thorough approach would require us to pick our way through other types such as newtype wrappers. Which led to the next approach: Attempt 2: custom traitThe second idea I had (though didn't explore) was to have a Attempt 3: serde
I prototyped this approach which included some nifty use of marker types: pub trait Style {}
pub mod style {
use crate::Style;
pub enum Form {}
impl Style for Form {}
pub enum SpaceDelimited {}
impl Style for SpaceDelimited {}
pub enum PipeDelimited {}
impl Style for PipeDelimited {}
pub enum DeepObject {}
impl Style for DeepObject {}
}
pub trait Explode {}
pub mod explode {
use crate::Explode;
pub enum True {}
impl Explode for True {}
pub enum False {}
impl Explode for False {}
} I thought that it would be neat to have progenitor generate query parameter code like this: .query(QuerySerialize::<style::Form, explode::True>::new("query-param-name", query_param)) This worked fine for Attempt 4: Serializer just for
|
While working with Scaleways API spec for Accounts, I encountered a array of strings in the URL. To me it is not clear how exactly it should work. The doc suggests it ends up as string in the URL
&project_ids=[string]
, so I assume they want it joined with a,
and not&project_ids=1&project_ids=2
.From Swaggers docs on OpenAPI serialization, the default style is
style: form
andexplode: true
aka&project_ids=1&project_ids=2
. That would, I think, require a change hereprogenitor/progenitor-impl/src/method.rs
Line 843 in 91564cf
Vec<_>
and iterate + push for that case.Any thoughts?
The text was updated successfully, but these errors were encountered: