mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-12-10 22:12:43 +00:00
Add support for string response deserialization (#12910)
* Add support for string response deserialization * updated samples * updated samples * realigned to master * fix: errors were not getting thrown * updated samples * fix: errors were not getting thrown * updated samples
This commit is contained in:
committed by
GitHub
parent
cf58ac0583
commit
b8524bee23
@@ -1,5 +0,0 @@
|
||||
* text=auto
|
||||
*.css linguist-vendored
|
||||
*.scss linguist-vendored
|
||||
*.js linguist-vendored
|
||||
CHANGELOG.md export-ignore
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Laminas\Stdlib\ErrorHandler;
|
||||
|
||||
class InternalServerError implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $responseGenerator;
|
||||
|
||||
/**
|
||||
* @param callable $responseGenerator
|
||||
*/
|
||||
public function __construct(callable $responseGenerator)
|
||||
{
|
||||
$this->responseGenerator = $responseGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$result = null;
|
||||
try {
|
||||
ErrorHandler::start();
|
||||
$result = $handler->handle($request);
|
||||
ErrorHandler::stop(true);
|
||||
}
|
||||
catch (\Throwable $error) {
|
||||
$result = $this->handleError($error);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function handleError(\Throwable $error): ResponseInterface
|
||||
{
|
||||
\error_log((string)$error);
|
||||
return $this->generateEmptyResponse()->withStatus(500, 'Internal server error');
|
||||
}
|
||||
|
||||
protected function generateEmptyResponse(): ResponseInterface
|
||||
{
|
||||
return ($this->responseGenerator)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 7):
|
||||
import typing
|
||||
|
||||
def is_generic(klass):
|
||||
""" Determine whether klass is a generic class """
|
||||
return type(klass) == typing.GenericMeta
|
||||
|
||||
def is_dict(klass):
|
||||
""" Determine whether klass is a Dict """
|
||||
return klass.__extra__ == dict
|
||||
|
||||
def is_list(klass):
|
||||
""" Determine whether klass is a List """
|
||||
return klass.__extra__ == list
|
||||
|
||||
else:
|
||||
|
||||
def is_generic(klass):
|
||||
""" Determine whether klass is a generic class """
|
||||
return hasattr(klass, '__origin__')
|
||||
|
||||
def is_dict(klass):
|
||||
""" Determine whether klass is a Dict """
|
||||
return klass.__origin__ == dict
|
||||
|
||||
def is_list(klass):
|
||||
""" Determine whether klass is a List """
|
||||
return klass.__origin__ == list
|
||||
|
||||
@@ -1,464 +0,0 @@
|
||||
use async_trait::async_trait;
|
||||
use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use hyper::{Body, Request, Response, service::Service, Uri};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{ErrorKind, Read};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString};
|
||||
use url::form_urlencoded;
|
||||
|
||||
|
||||
use crate::models;
|
||||
use crate::header;
|
||||
|
||||
/// https://url.spec.whatwg.org/#fragment-percent-encode-set
|
||||
#[allow(dead_code)]
|
||||
const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
|
||||
.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
|
||||
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
#[allow(dead_code)]
|
||||
const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|');
|
||||
|
||||
use crate::{Api,
|
||||
OpGetResponse
|
||||
};
|
||||
|
||||
/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes.
|
||||
fn into_base_path(input: impl TryInto<Uri, Error=hyper::http::uri::InvalidUri>, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
|
||||
// First convert to Uri, since a base path is a subset of Uri.
|
||||
let uri = input.try_into()?;
|
||||
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
|
||||
// Check the scheme if necessary
|
||||
if let Some(correct_scheme) = correct_scheme {
|
||||
if scheme != correct_scheme {
|
||||
return Err(ClientInitError::InvalidScheme);
|
||||
}
|
||||
}
|
||||
|
||||
let host = uri.host().ok_or_else(|| ClientInitError::MissingHost)?;
|
||||
let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default();
|
||||
Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/')))
|
||||
}
|
||||
|
||||
/// A client that implements the API by making HTTP calls out to a server.
|
||||
pub struct Client<S, C> where
|
||||
S: Service<
|
||||
(Request<Body>, C),
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
C: Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Inner service
|
||||
client_service: S,
|
||||
|
||||
/// Base path of the API
|
||||
base_path: String,
|
||||
|
||||
/// Marker
|
||||
marker: PhantomData<fn(C)>,
|
||||
}
|
||||
|
||||
impl<S, C> fmt::Debug for Client<S, C> where
|
||||
S: Service<
|
||||
(Request<Body>, C),
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
C: Clone + Send + Sync + 'static
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Client {{ base_path: {} }}", self.base_path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, C> Clone for Client<S, C> where
|
||||
S: Service<
|
||||
(Request<Body>, C),
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
C: Clone + Send + Sync + 'static
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
client_service: self.client_service.clone(),
|
||||
base_path: self.base_path.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Connector, C> Client<DropContextService<hyper::client::Client<Connector, Body>, C>, C> where
|
||||
Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
C: Clone + Send + Sync + 'static,
|
||||
{
|
||||
/// Create a client with a custom implementation of hyper::client::Connect.
|
||||
///
|
||||
/// Intended for use with custom implementations of connect for e.g. protocol logging
|
||||
/// or similar functionality which requires wrapping the transport layer. When wrapping a TCP connection,
|
||||
/// this function should be used in conjunction with `swagger::Connector::builder()`.
|
||||
///
|
||||
/// For ordinary tcp connections, prefer the use of `try_new_http`, `try_new_https`
|
||||
/// and `try_new_https_mutual`, to avoid introducing a dependency on the underlying transport layer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
/// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")`
|
||||
/// * `connector` - Implementation of `hyper::client::Connect` to use for the client
|
||||
pub fn try_new_with_connector(
|
||||
base_path: &str,
|
||||
protocol: Option<&'static str>,
|
||||
connector: Connector,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let client_service = hyper::client::Client::builder().build(connector);
|
||||
let client_service = DropContextService::new(client_service);
|
||||
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, protocol)?,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HyperClient {
|
||||
Http(hyper::client::Client<hyper::client::HttpConnector, Body>),
|
||||
Https(hyper::client::Client<HttpsConnector, Body>),
|
||||
}
|
||||
|
||||
impl Service<Request<Body>> for HyperClient {
|
||||
type Response = Response<Body>;
|
||||
type Error = hyper::Error;
|
||||
type Future = hyper::client::ResponseFuture;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.poll_ready(cx),
|
||||
HyperClient::Https(client) => client.poll_ready(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.call(req),
|
||||
HyperClient::Https(client) => client.call(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Client<DropContextService<HyperClient, C>, C> where
|
||||
C: Clone + Send + Sync + 'static,
|
||||
{
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
let uri = Uri::from_str(base_path)?;
|
||||
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
let scheme = scheme.to_ascii_lowercase();
|
||||
|
||||
let connector = Connector::builder();
|
||||
|
||||
let client_service = match scheme.as_str() {
|
||||
"http" => {
|
||||
HyperClient::Http(hyper::client::Client::builder().build(connector.build()))
|
||||
},
|
||||
"https" => {
|
||||
let connector = connector.https()
|
||||
.build()
|
||||
.map_err(|e| ClientInitError::SslError(e))?;
|
||||
HyperClient::Https(hyper::client::Client::builder().build(connector))
|
||||
},
|
||||
_ => {
|
||||
return Err(ClientInitError::InvalidScheme);
|
||||
}
|
||||
};
|
||||
|
||||
let client_service = DropContextService::new(client_service);
|
||||
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Client<DropContextService<hyper::client::Client<hyper::client::HttpConnector, Body>, C>, C> where
|
||||
C: Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new_http(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
let http_connector = Connector::builder().build();
|
||||
|
||||
Self::try_new_with_connector(base_path, Some("http"), http_connector)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
type HttpsConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
impl<C> Client<DropContextService<hyper::client::Client<HttpsConnector, Body>, C>, C> where
|
||||
C: Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Create a client with a TLS connection to the server
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
pub fn try_new_https(base_path: &str) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let https_connector = Connector::builder()
|
||||
.https()
|
||||
.build()
|
||||
.map_err(|e| ClientInitError::SslError(e))?;
|
||||
Self::try_new_with_connector(base_path, Some("https"), https_connector)
|
||||
}
|
||||
|
||||
/// Create a client with a TLS connection to the server using a pinned certificate
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
pub fn try_new_https_pinned<CA>(
|
||||
base_path: &str,
|
||||
ca_certificate: CA,
|
||||
) -> Result<Self, ClientInitError>
|
||||
where
|
||||
CA: AsRef<Path>,
|
||||
{
|
||||
let https_connector = Connector::builder()
|
||||
.https()
|
||||
.pin_server_certificate(ca_certificate)
|
||||
.build()
|
||||
.map_err(|e| ClientInitError::SslError(e))?;
|
||||
Self::try_new_with_connector(base_path, Some("https"), https_connector)
|
||||
}
|
||||
|
||||
/// Create a client with a mutually authenticated TLS connection to the server.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
/// * `client_key` - Path to the client private key
|
||||
/// * `client_certificate` - Path to the client's public certificate associated with the private key
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
pub fn try_new_https_mutual<CA, K, D>(
|
||||
base_path: &str,
|
||||
ca_certificate: CA,
|
||||
client_key: K,
|
||||
client_certificate: D,
|
||||
) -> Result<Self, ClientInitError>
|
||||
where
|
||||
CA: AsRef<Path>,
|
||||
K: AsRef<Path>,
|
||||
D: AsRef<Path>,
|
||||
{
|
||||
let https_connector = Connector::builder()
|
||||
.https()
|
||||
.pin_server_certificate(ca_certificate)
|
||||
.client_authentication(client_key, client_certificate)
|
||||
.build()
|
||||
.map_err(|e| ClientInitError::SslError(e))?;
|
||||
Self::try_new_with_connector(base_path, Some("https"), https_connector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, C> Client<S, C> where
|
||||
S: Service<
|
||||
(Request<Body>, C),
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
C: Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `hyper::service::Service` /
|
||||
/// `tower::Service`
|
||||
///
|
||||
/// This allows adding custom wrappers around the underlying transport, for example for logging.
|
||||
pub fn try_new_with_client_service(
|
||||
client_service: S,
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type failing to create a Client
|
||||
#[derive(Debug)]
|
||||
pub enum ClientInitError {
|
||||
/// Invalid URL Scheme
|
||||
InvalidScheme,
|
||||
|
||||
/// Invalid URI
|
||||
InvalidUri(hyper::http::uri::InvalidUri),
|
||||
|
||||
/// Missing Hostname
|
||||
MissingHost,
|
||||
|
||||
/// SSL Connection Error
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
SslError(native_tls::Error),
|
||||
|
||||
/// SSL Connection Error
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
SslError(openssl::error::ErrorStack),
|
||||
}
|
||||
|
||||
impl From<hyper::http::uri::InvalidUri> for ClientInitError {
|
||||
fn from(err: hyper::http::uri::InvalidUri) -> ClientInitError {
|
||||
ClientInitError::InvalidUri(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ClientInitError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let s: &dyn fmt::Debug = self;
|
||||
s.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ClientInitError {
|
||||
fn description(&self) -> &str {
|
||||
"Failed to produce a hyper client."
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, C> Api<C> for Client<S, C> where
|
||||
S: Service<
|
||||
(Request<Body>, C),
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
C: Has<XSpanIdString> + Clone + Send + Sync + 'static,
|
||||
{
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
|
||||
match self.client_service.clone().poll_ready(cx) {
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
|
||||
Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
async fn op_get(
|
||||
&self,
|
||||
param_op_get_request: models::OpGetRequest,
|
||||
context: &C) -> Result<OpGetResponse, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
"{}/op",
|
||||
self.base_path
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match Request::builder()
|
||||
.method("GET")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
// Body parameter
|
||||
let body = serde_json::to_string(¶m_op_get_request).expect("impossible to fail to serialize");
|
||||
|
||||
*request.body_mut() = Body::from(body);
|
||||
|
||||
let header = "application/json";
|
||||
request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
|
||||
});
|
||||
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
let mut response = client_service.call((request, context.clone()))
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
200 => {
|
||||
let body = response.into_body();
|
||||
Ok(
|
||||
OpGetResponse::OK
|
||||
)
|
||||
}
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.into_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# AnotherXmlArray
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user