cleanup and documentation (#67)
This commit is contained in:
parent
3cd1eae3f5
commit
eec8526ba5
|
@ -11,8 +11,7 @@ use bytes::Bytes;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
/// Represents a streaming, untyped byte stream for both success and error
|
/// Represents an untyped byte stream for both success and error responses.
|
||||||
/// responses.
|
|
||||||
pub type ByteStream =
|
pub type ByteStream =
|
||||||
Pin<Box<dyn Stream<Item = reqwest::Result<Bytes>> + Send>>;
|
Pin<Box<dyn Stream<Item = reqwest::Result<Bytes>> + Send>>;
|
||||||
|
|
||||||
|
@ -136,6 +135,9 @@ impl<T: std::fmt::Debug> std::fmt::Debug for ResponseValue<T> {
|
||||||
/// or an enum if there are multiple valid error types. It can be the unit type
|
/// or an enum if there are multiple valid error types. It can be the unit type
|
||||||
/// if there are no structured returns expected.
|
/// if there are no structured returns expected.
|
||||||
pub enum Error<E = ()> {
|
pub enum Error<E = ()> {
|
||||||
|
/// The request did not conform to API requirements.
|
||||||
|
InvalidRequest(String),
|
||||||
|
|
||||||
/// A server error either with the data, or with the connection.
|
/// A server error either with the data, or with the connection.
|
||||||
CommunicationError(reqwest::Error),
|
CommunicationError(reqwest::Error),
|
||||||
|
|
||||||
|
@ -155,6 +157,7 @@ impl<E> Error<E> {
|
||||||
/// Returns the status code, if the error was generated from a response.
|
/// Returns the status code, if the error was generated from a response.
|
||||||
pub fn status(&self) -> Option<reqwest::StatusCode> {
|
pub fn status(&self) -> Option<reqwest::StatusCode> {
|
||||||
match self {
|
match self {
|
||||||
|
Error::InvalidRequest(_) => None,
|
||||||
Error::CommunicationError(e) => e.status(),
|
Error::CommunicationError(e) => e.status(),
|
||||||
Error::ErrorResponse(rv) => Some(rv.status()),
|
Error::ErrorResponse(rv) => Some(rv.status()),
|
||||||
Error::InvalidResponsePayload(e) => e.status(),
|
Error::InvalidResponsePayload(e) => e.status(),
|
||||||
|
@ -166,6 +169,7 @@ impl<E> Error<E> {
|
||||||
/// handling with APIs that distinguish various error response bodies.
|
/// handling with APIs that distinguish various error response bodies.
|
||||||
pub fn into_untyped(self) -> Error {
|
pub fn into_untyped(self) -> Error {
|
||||||
match self {
|
match self {
|
||||||
|
Error::InvalidRequest(s) => Error::InvalidRequest(s),
|
||||||
Error::CommunicationError(e) => Error::CommunicationError(e),
|
Error::CommunicationError(e) => Error::CommunicationError(e),
|
||||||
Error::ErrorResponse(ResponseValue {
|
Error::ErrorResponse(ResponseValue {
|
||||||
inner: _,
|
inner: _,
|
||||||
|
@ -193,17 +197,20 @@ impl<E> From<reqwest::Error> for Error<E> {
|
||||||
impl<E> std::fmt::Display for Error<E> {
|
impl<E> std::fmt::Display for Error<E> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Error::InvalidRequest(s) => {
|
||||||
|
write!(f, "Invalid Request: {}", s)
|
||||||
|
}
|
||||||
Error::CommunicationError(e) => {
|
Error::CommunicationError(e) => {
|
||||||
write!(f, "Communication Error {}", e)
|
write!(f, "Communication Error: {}", e)
|
||||||
}
|
}
|
||||||
Error::ErrorResponse(_) => {
|
Error::ErrorResponse(_) => {
|
||||||
write!(f, "Error Response")
|
write!(f, "Error Response")
|
||||||
}
|
}
|
||||||
Error::InvalidResponsePayload(e) => {
|
Error::InvalidResponsePayload(e) => {
|
||||||
write!(f, "Invalid Response Payload {}", e)
|
write!(f, "Invalid Response Payload: {}", e)
|
||||||
}
|
}
|
||||||
Error::UnexpectedResponse(r) => {
|
Error::UnexpectedResponse(r) => {
|
||||||
write!(f, "Unexpected Response {:?}", r)
|
write!(f, "Unexpected Response: {:?}", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,12 @@ pub enum Error {
|
||||||
BadValue(String, serde_json::Value),
|
BadValue(String, serde_json::Value),
|
||||||
#[error("type error")]
|
#[error("type error")]
|
||||||
TypeError(#[from] typify::Error),
|
TypeError(#[from] typify::Error),
|
||||||
#[error("XXX")]
|
#[error("unexpected or unhandled format in the OpenAPI document")]
|
||||||
BadConversion(String),
|
UnexpectedFormat(String),
|
||||||
#[error("invalid operation path")]
|
#[error("invalid operation path")]
|
||||||
InvalidPath(String),
|
InvalidPath(String),
|
||||||
//#[error("unknown")]
|
#[error("invalid operation path")]
|
||||||
//Unknown,
|
InternalError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
@ -84,7 +84,7 @@ impl Generator {
|
||||||
.flat_map(|(path, ref_or_item)| {
|
.flat_map(|(path, ref_or_item)| {
|
||||||
// Exclude externally defined path items.
|
// Exclude externally defined path items.
|
||||||
let item = ref_or_item.as_item().unwrap();
|
let item = ref_or_item.as_item().unwrap();
|
||||||
// TODO punt on paramters that apply to all path items for now.
|
// TODO punt on parameters that apply to all path items for now.
|
||||||
assert!(item.parameters.is_empty());
|
assert!(item.parameters.is_empty());
|
||||||
item.iter().map(move |(method, operation)| {
|
item.iter().map(move |(method, operation)| {
|
||||||
(path.as_str(), method, operation)
|
(path.as_str(), method, operation)
|
||||||
|
@ -102,7 +102,7 @@ impl Generator {
|
||||||
|
|
||||||
let methods = raw_methods
|
let methods = raw_methods
|
||||||
.iter()
|
.iter()
|
||||||
.map(|method| self.process_method(method))
|
.map(|method| self.positional_method(method))
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let mut types = self
|
let mut types = self
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::{BTreeSet, HashMap},
|
collections::{BTreeSet, HashMap},
|
||||||
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use openapiv3::{Components, Response, StatusCode};
|
use openapiv3::{Components, Response, StatusCode};
|
||||||
|
@ -17,17 +18,62 @@ use crate::{
|
||||||
};
|
};
|
||||||
use crate::{to_schema::ToSchema, util::ReferenceOrExt};
|
use crate::{to_schema::ToSchema, util::ReferenceOrExt};
|
||||||
|
|
||||||
|
/// The intermediate representation of an operation that will become a method.
|
||||||
pub(crate) struct OperationMethod {
|
pub(crate) struct OperationMethod {
|
||||||
operation_id: String,
|
operation_id: String,
|
||||||
method: String,
|
method: HttpMethod,
|
||||||
path: PathTemplate,
|
path: PathTemplate,
|
||||||
summary: Option<String>,
|
summary: Option<String>,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
params: Vec<OperationParameter>,
|
params: Vec<OperationParameter>,
|
||||||
|
raw_body_param: bool,
|
||||||
responses: Vec<OperationResponse>,
|
responses: Vec<OperationResponse>,
|
||||||
dropshot_paginated: Option<DropshotPagination>,
|
dropshot_paginated: Option<DropshotPagination>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum HttpMethod {
|
||||||
|
Get,
|
||||||
|
Put,
|
||||||
|
Post,
|
||||||
|
Delete,
|
||||||
|
Options,
|
||||||
|
Head,
|
||||||
|
Patch,
|
||||||
|
Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for HttpMethod {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
match s {
|
||||||
|
"get" => Ok(Self::Get),
|
||||||
|
"put" => Ok(Self::Put),
|
||||||
|
"post" => Ok(Self::Post),
|
||||||
|
"delete" => Ok(Self::Delete),
|
||||||
|
"options" => Ok(Self::Options),
|
||||||
|
"head" => Ok(Self::Head),
|
||||||
|
"patch" => Ok(Self::Patch),
|
||||||
|
"trace" => Ok(Self::Trace),
|
||||||
|
_ => Err(Error::InternalError(format!("bad method: {}", s))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl HttpMethod {
|
||||||
|
fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
HttpMethod::Get => "get",
|
||||||
|
HttpMethod::Put => "put",
|
||||||
|
HttpMethod::Post => "post",
|
||||||
|
HttpMethod::Delete => "delete",
|
||||||
|
HttpMethod::Options => "options",
|
||||||
|
HttpMethod::Head => "head",
|
||||||
|
HttpMethod::Patch => "patch",
|
||||||
|
HttpMethod::Trace => "trace",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct DropshotPagination {
|
struct DropshotPagination {
|
||||||
item: TypeId,
|
item: TypeId,
|
||||||
}
|
}
|
||||||
|
@ -154,7 +200,7 @@ impl Generator {
|
||||||
let operation_id = operation.operation_id.as_ref().unwrap();
|
let operation_id = operation.operation_id.as_ref().unwrap();
|
||||||
|
|
||||||
let mut query: Vec<(String, bool)> = Vec::new();
|
let mut query: Vec<(String, bool)> = Vec::new();
|
||||||
let mut raw_params = operation
|
let mut params = operation
|
||||||
.parameters
|
.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|parameter| {
|
.map(|parameter| {
|
||||||
|
@ -189,14 +235,10 @@ impl Generator {
|
||||||
}
|
}
|
||||||
openapiv3::Parameter::Query {
|
openapiv3::Parameter::Query {
|
||||||
parameter_data,
|
parameter_data,
|
||||||
allow_reserved: _,
|
allow_reserved: _, // We always encode reserved chars
|
||||||
style: openapiv3::QueryStyle::Form,
|
style: openapiv3::QueryStyle::Form,
|
||||||
allow_empty_value,
|
allow_empty_value: _, // Irrelevant for this client
|
||||||
} => {
|
} => {
|
||||||
if let Some(true) = allow_empty_value {
|
|
||||||
todo!("allow empty value is a no go");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut schema = parameter_data.schema()?.to_schema();
|
let mut schema = parameter_data.schema()?.to_schema();
|
||||||
let name = sanitize(
|
let name = sanitize(
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -229,13 +271,39 @@ impl Generator {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
x => todo!("unhandled parameter type: {:#?}", x),
|
|
||||||
|
openapiv3::Parameter::Path { style, .. } => {
|
||||||
|
Err(Error::UnexpectedFormat(format!(
|
||||||
|
"unsupported style of path parameter {:#?}",
|
||||||
|
style,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
openapiv3::Parameter::Query { style, .. } => {
|
||||||
|
Err(Error::UnexpectedFormat(format!(
|
||||||
|
"unsupported style of query parameter {:#?}",
|
||||||
|
style,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
header @ openapiv3::Parameter::Header { .. } => {
|
||||||
|
Err(Error::UnexpectedFormat(format!(
|
||||||
|
"header parameters are not supported {:#?}",
|
||||||
|
header,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
cookie @ openapiv3::Parameter::Cookie { .. } => {
|
||||||
|
Err(Error::UnexpectedFormat(format!(
|
||||||
|
"cookie parameters are not supported {:#?}",
|
||||||
|
cookie,
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
let mut raw_body_param = false;
|
||||||
if let Some(b) = &operation.request_body {
|
if let Some(b) = &operation.request_body {
|
||||||
let b = b.item(components)?;
|
let b = b.item(components)?;
|
||||||
let typ = if b.is_binary(components)? {
|
let typ = if b.is_binary(components)? {
|
||||||
|
raw_body_param = true;
|
||||||
OperationParameterType::RawBody
|
OperationParameterType::RawBody
|
||||||
} else {
|
} else {
|
||||||
let mt = b.content_json()?;
|
let mt = b.content_json()?;
|
||||||
|
@ -261,7 +329,7 @@ impl Generator {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
raw_params.push(OperationParameter {
|
params.push(OperationParameter {
|
||||||
name: "body".to_string(),
|
name: "body".to_string(),
|
||||||
api_name: "body".to_string(),
|
api_name: "body".to_string(),
|
||||||
description: b.description.clone(),
|
description: b.description.clone(),
|
||||||
|
@ -272,7 +340,7 @@ impl Generator {
|
||||||
let tmp = crate::template::parse(path)?;
|
let tmp = crate::template::parse(path)?;
|
||||||
let names = tmp.names();
|
let names = tmp.names();
|
||||||
|
|
||||||
sort_params(&mut raw_params, &names);
|
sort_params(&mut params, &names);
|
||||||
|
|
||||||
let mut success = false;
|
let mut success = false;
|
||||||
|
|
||||||
|
@ -377,30 +445,32 @@ impl Generator {
|
||||||
}
|
}
|
||||||
|
|
||||||
let dropshot_paginated =
|
let dropshot_paginated =
|
||||||
self.dropshot_pagination_data(operation, &raw_params, &responses);
|
self.dropshot_pagination_data(operation, ¶ms, &responses);
|
||||||
|
|
||||||
Ok(OperationMethod {
|
Ok(OperationMethod {
|
||||||
operation_id: sanitize(operation_id, Case::Snake),
|
operation_id: sanitize(operation_id, Case::Snake),
|
||||||
method: method.to_string(),
|
method: HttpMethod::from_str(method)?,
|
||||||
path: tmp,
|
path: tmp,
|
||||||
summary: operation.summary.clone().filter(|s| !s.is_empty()),
|
summary: operation.summary.clone().filter(|s| !s.is_empty()),
|
||||||
description: operation
|
description: operation
|
||||||
.description
|
.description
|
||||||
.clone()
|
.clone()
|
||||||
.filter(|s| !s.is_empty()),
|
.filter(|s| !s.is_empty()),
|
||||||
params: raw_params,
|
params,
|
||||||
|
raw_body_param,
|
||||||
responses,
|
responses,
|
||||||
dropshot_paginated,
|
dropshot_paginated,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process_method(
|
pub(crate) fn positional_method(
|
||||||
&mut self,
|
&mut self,
|
||||||
method: &OperationMethod,
|
method: &OperationMethod,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let operation_id = format_ident!("{}", method.operation_id);
|
let operation_id = format_ident!("{}", method.operation_id);
|
||||||
let mut bounds_items: Vec<TokenStream> = Vec::new();
|
|
||||||
let typed_params = method
|
// Render each parameter as it will appear in the method signature.
|
||||||
|
let params = method
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|param| {
|
.map(|param| {
|
||||||
|
@ -412,23 +482,22 @@ impl Generator {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parameter_ident_with_lifetime("a"),
|
.parameter_ident_with_lifetime("a"),
|
||||||
OperationParameterType::RawBody => {
|
OperationParameterType::RawBody => {
|
||||||
bounds_items.push(quote! { B: Into<reqwest::Body> });
|
|
||||||
quote! { B }
|
quote! { B }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(
|
quote! {
|
||||||
param,
|
#name: #typ
|
||||||
quote! {
|
}
|
||||||
#name: #typ
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let params = typed_params.iter().map(|(_, stream)| stream);
|
let bounds = if method.raw_body_param {
|
||||||
|
quote! { <'a, B: Into<reqwest::Body> > }
|
||||||
let bounds = quote! { < 'a, #(#bounds_items),* > };
|
} else {
|
||||||
|
quote! { <'a> }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate code for query parameters.
|
||||||
let query_items = method
|
let query_items = method
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -465,19 +534,21 @@ impl Generator {
|
||||||
(query_build, query_use)
|
(query_build, query_use)
|
||||||
};
|
};
|
||||||
|
|
||||||
let url_path = method.path.compile(
|
// Generate the path rename map; then use it to generate code for
|
||||||
method
|
// assigning the path parameters to the `url` variable.
|
||||||
.params
|
let url_renames = method
|
||||||
.iter()
|
.params
|
||||||
.filter_map(|param| match ¶m.kind {
|
.iter()
|
||||||
OperationParameterKind::Path => {
|
.filter_map(|param| match ¶m.kind {
|
||||||
Some((¶m.api_name, ¶m.name))
|
OperationParameterKind::Path => {
|
||||||
}
|
Some((¶m.api_name, ¶m.name))
|
||||||
_ => None,
|
}
|
||||||
})
|
_ => None,
|
||||||
.collect(),
|
})
|
||||||
);
|
.collect();
|
||||||
|
let url_path = method.path.compile(url_renames);
|
||||||
|
|
||||||
|
// Generate code to handle the body...
|
||||||
let body_func =
|
let body_func =
|
||||||
method.params.iter().filter_map(|param| match ¶m.kind {
|
method.params.iter().filter_map(|param| match ¶m.kind {
|
||||||
OperationParameterKind::Body => match ¶m.typ {
|
OperationParameterKind::Body => match ¶m.typ {
|
||||||
|
@ -490,7 +561,7 @@ impl Generator {
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
|
// ... and there can be at most one body.
|
||||||
assert!(body_func.clone().count() <= 1);
|
assert!(body_func.clone().count() <= 1);
|
||||||
|
|
||||||
let (success_response_items, response_type) = self.extract_responses(
|
let (success_response_items, response_type) = self.extract_responses(
|
||||||
|
@ -604,8 +675,7 @@ impl Generator {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO validate that method is one of the expected methods.
|
let method_func = format_ident!("{}", method.method.as_str());
|
||||||
let method_func = format_ident!("{}", method.method.to_lowercase());
|
|
||||||
|
|
||||||
let method_impl = quote! {
|
let method_impl = quote! {
|
||||||
#[doc = #doc_comment]
|
#[doc = #doc_comment]
|
||||||
|
@ -636,7 +706,7 @@ impl Generator {
|
||||||
// These will be of the form...
|
// These will be of the form...
|
||||||
// 201 => ResponseValue::from_response(response).await,
|
// 201 => ResponseValue::from_response(response).await,
|
||||||
// 200..299 => ResponseValue::empty(response),
|
// 200..299 => ResponseValue::empty(response),
|
||||||
// TODO this isn't implemented
|
// TODO this kind of enumerated response isn't implemented
|
||||||
// ... or in the case of an operation with multiple
|
// ... or in the case of an operation with multiple
|
||||||
// successful response types...
|
// successful response types...
|
||||||
// 200 => {
|
// 200 => {
|
||||||
|
@ -677,18 +747,19 @@ impl Generator {
|
||||||
|
|
||||||
// The parameters are the same as those to the paged method, but
|
// The parameters are the same as those to the paged method, but
|
||||||
// without "page_token"
|
// without "page_token"
|
||||||
let stream_params =
|
let stream_params = method.params.iter().zip(params).filter_map(
|
||||||
typed_params.iter().filter_map(|(param, stream)| {
|
|(param, stream)| {
|
||||||
if param.api_name.as_str() == "page_token" {
|
if param.name.as_str() == "page_token" {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(stream)
|
Some(stream)
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// The values passed to get the first page are the inputs to the
|
// The values passed to get the first page are the inputs to the
|
||||||
// stream method with "None" for the page_token.
|
// stream method with "None" for the page_token.
|
||||||
let first_params = typed_params.iter().map(|(param, _)| {
|
let first_params = method.params.iter().map(|param| {
|
||||||
if param.api_name.as_str() == "page_token" {
|
if param.api_name.as_str() == "page_token" {
|
||||||
// The page_token is None when getting the first page.
|
// The page_token is None when getting the first page.
|
||||||
quote! { None }
|
quote! { None }
|
||||||
|
@ -702,7 +773,7 @@ impl Generator {
|
||||||
// - the state variable for the page_token
|
// - the state variable for the page_token
|
||||||
// - None for all other query parameters
|
// - None for all other query parameters
|
||||||
// - The method inputs for non-query parameters
|
// - The method inputs for non-query parameters
|
||||||
let step_params = typed_params.iter().map(|(param, _)| {
|
let step_params = method.params.iter().map(|param| {
|
||||||
if param.api_name.as_str() == "page_token" {
|
if param.api_name.as_str() == "page_token" {
|
||||||
quote! { state.as_deref() }
|
quote! { state.as_deref() }
|
||||||
} else if let OperationParameterKind::Query(_) = param.kind {
|
} else if let OperationParameterKind::Query(_) = param.kind {
|
||||||
|
@ -987,7 +1058,7 @@ fn make_doc_comment(method: &OperationMethod) -> String {
|
||||||
|
|
||||||
buf.push_str(&format!(
|
buf.push_str(&format!(
|
||||||
"Sends a `{}` request to `{}`",
|
"Sends a `{}` request to `{}`",
|
||||||
method.method.to_ascii_uppercase(),
|
method.method.as_str().to_ascii_uppercase(),
|
||||||
method.path.to_string(),
|
method.path.to_string(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1026,7 +1097,7 @@ fn make_stream_doc_comment(method: &OperationMethod) -> String {
|
||||||
|
|
||||||
buf.push_str(&format!(
|
buf.push_str(&format!(
|
||||||
"Sends repeated `{}` requests to `{}` until there are no more results.",
|
"Sends repeated `{}` requests to `{}` until there are no more results.",
|
||||||
method.method.to_ascii_uppercase(),
|
method.method.as_str().to_ascii_uppercase(),
|
||||||
method.path.to_string(),
|
method.path.to_string(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1171,9 +1242,9 @@ impl ParameterDataExt for openapiv3::ParameterData {
|
||||||
fn schema(&self) -> Result<&openapiv3::ReferenceOr<openapiv3::Schema>> {
|
fn schema(&self) -> Result<&openapiv3::ReferenceOr<openapiv3::Schema>> {
|
||||||
match &self.format {
|
match &self.format {
|
||||||
openapiv3::ParameterSchemaOrContent::Schema(s) => Ok(s),
|
openapiv3::ParameterSchemaOrContent::Schema(s) => Ok(s),
|
||||||
x => {
|
openapiv3::ParameterSchemaOrContent::Content(c) => Err(
|
||||||
Err(Error::BadConversion(format!("XXX param format {:#?}", x)))
|
Error::UnexpectedFormat(format!("unexpected content {:#?}", c)),
|
||||||
}
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue