/* * OpenAPI Petstore * * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. * * The version of the OpenAPI document: 1.0.0 * Generated by: https://github.com/openapitools/openapi-generator.git */ using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Text; using System.Threading; using System.Text.RegularExpressions; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; using RestSharp; using RestSharp.Deserializers; using RestSharpMethod = RestSharp.Method; using Polly; namespace Org.OpenAPITools.Client { /// /// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON. /// internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer { private readonly IReadableConfiguration _configuration; private static readonly string _contentType = "application/json"; private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings { // OpenAPI generated types generally hide default constructors. ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy { OverrideSpecifiedNames = false } } }; public CustomJsonCodec(IReadableConfiguration configuration) { _configuration = configuration; } public CustomJsonCodec(JsonSerializerSettings serializerSettings, IReadableConfiguration configuration) { _serializerSettings = serializerSettings; _configuration = configuration; } /// /// Serialize the object into a JSON string. /// /// Object to be serialized. /// A JSON string. public string Serialize(object obj) { if (obj != null && obj is Org.OpenAPITools.Models.AbstractOpenAPISchema) { // the object to be serialized is an oneOf/anyOf schema return ((Org.OpenAPITools.Models.AbstractOpenAPISchema)obj).ToJson(); } else { return JsonConvert.SerializeObject(obj, _serializerSettings); } } public T Deserialize(IRestResponse response) { var result = (T)Deserialize(response, typeof(T)); return result; } /// /// Deserialize the JSON string into a proper object. /// /// The HTTP response. /// Object type. /// Object representation of the JSON string. internal object Deserialize(IRestResponse response, Type type) { if (type == typeof(byte[])) // return byte array { return response.RawBytes; } // TODO: ? if (type.IsAssignableFrom(typeof(Stream))) if (type == typeof(Stream)) { var bytes = response.RawBytes; if (response.Headers != null) { var filePath = string.IsNullOrEmpty(_configuration.TempFolderPath) ? Path.GetTempPath() : _configuration.TempFolderPath; var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$"); foreach (var header in response.Headers) { var match = regex.Match(header.ToString()); if (match.Success) { string fileName = filePath + ClientUtils.SanitizeFilename(match.Groups[1].Value.Replace("\"", "").Replace("'", "")); File.WriteAllBytes(fileName, bytes); return new FileStream(fileName, FileMode.Open); } } } var stream = new MemoryStream(bytes); return stream; } if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object { return DateTime.Parse(response.Content, null, System.Globalization.DateTimeStyles.RoundtripKind); } if (type == typeof(string) || type.Name.StartsWith("System.Nullable")) // return primitive type { return Convert.ChangeType(response.Content, type); } // at this point, it must be a model (json) try { return JsonConvert.DeserializeObject(response.Content, type, _serializerSettings); } catch (Exception e) { throw new ApiException(500, e.Message); } } public string RootElement { get; set; } public string Namespace { get; set; } public string DateFormat { get; set; } public string ContentType { get { return _contentType; } set { throw new InvalidOperationException("Not allowed to set content type."); } } } /// /// Provides a default implementation of an Api client (both synchronous and asynchronous implementations), /// encapsulating general REST accessor use cases. /// public partial class ApiClient : ISynchronousClient, IAsynchronousClient { private readonly string _baseUrl; /// /// Specifies the settings on a object. /// These settings can be adjusted to accommodate custom serialization rules. /// public JsonSerializerSettings SerializerSettings { get; set; } = new JsonSerializerSettings { // OpenAPI generated types generally hide default constructors. ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy { OverrideSpecifiedNames = false } } }; /// /// Allows for extending request processing for generated code. /// /// The RestSharp request object partial void InterceptRequest(IRestRequest request); /// /// Allows for extending response processing for generated code. /// /// The RestSharp request object /// The RestSharp response object partial void InterceptResponse(IRestRequest request, IRestResponse response); /// /// Initializes a new instance of the , defaulting to the global configurations' base url. /// public ApiClient() { _baseUrl = Org.OpenAPITools.Client.GlobalConfiguration.Instance.BasePath; } /// /// Initializes a new instance of the /// /// The target service's base path in URL format. /// public ApiClient(string basePath) { if (string.IsNullOrEmpty(basePath)) throw new ArgumentException("basePath cannot be empty"); _baseUrl = basePath; } /// /// Constructs the RestSharp version of an http method /// /// Swagger Client Custom HttpMethod /// RestSharp's HttpMethod instance. /// private RestSharpMethod Method(HttpMethod method) { RestSharpMethod other; switch (method) { case HttpMethod.Get: other = RestSharpMethod.GET; break; case HttpMethod.Post: other = RestSharpMethod.POST; break; case HttpMethod.Put: other = RestSharpMethod.PUT; break; case HttpMethod.Delete: other = RestSharpMethod.DELETE; break; case HttpMethod.Head: other = RestSharpMethod.HEAD; break; case HttpMethod.Options: other = RestSharpMethod.OPTIONS; break; case HttpMethod.Patch: other = RestSharpMethod.PATCH; break; default: throw new ArgumentOutOfRangeException("method", method, null); } return other; } /// /// Provides all logic for constructing a new RestSharp . /// At this point, all information for querying the service is known. Here, it is simply /// mapped into the RestSharp request. /// /// The http verb. /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// [private] A new RestRequest instance. /// private RestRequest NewRequest( HttpMethod method, string path, RequestOptions options, IReadableConfiguration configuration) { if (path == null) throw new ArgumentNullException("path"); if (options == null) throw new ArgumentNullException("options"); if (configuration == null) throw new ArgumentNullException("configuration"); RestRequest request = new RestRequest(Method(method)) { Resource = path, JsonSerializer = new CustomJsonCodec(SerializerSettings, configuration) }; if (options.PathParameters != null) { foreach (var pathParam in options.PathParameters) { request.AddParameter(pathParam.Key, pathParam.Value, ParameterType.UrlSegment); } } if (options.QueryParameters != null) { foreach (var queryParam in options.QueryParameters) { foreach (var value in queryParam.Value) { request.AddQueryParameter(queryParam.Key, value); } } } if (configuration.DefaultHeaders != null) { foreach (var headerParam in configuration.DefaultHeaders) { request.AddHeader(headerParam.Key, headerParam.Value); } } if (options.HeaderParameters != null) { foreach (var headerParam in options.HeaderParameters) { foreach (var value in headerParam.Value) { request.AddHeader(headerParam.Key, value); } } } if (options.FormParameters != null) { foreach (var formParam in options.FormParameters) { request.AddParameter(formParam.Key, formParam.Value); } } if (options.Data != null) { if (options.Data is Stream stream) { var contentType = "application/octet-stream"; if (options.HeaderParameters != null) { var contentTypes = options.HeaderParameters["Content-Type"]; contentType = contentTypes[0]; } var bytes = ClientUtils.ReadAsBytes(stream); request.AddParameter(contentType, bytes, ParameterType.RequestBody); } else { if (options.HeaderParameters != null) { var contentTypes = options.HeaderParameters["Content-Type"]; if (contentTypes == null || contentTypes.Any(header => header.Contains("application/json"))) { request.RequestFormat = DataFormat.Json; } else { // TODO: Generated client user should add additional handlers. RestSharp only supports XML and JSON, with XML as default. } } else { // Here, we'll assume JSON APIs are more common. XML can be forced by adding produces/consumes to openapi spec explicitly. request.RequestFormat = DataFormat.Json; } request.AddJsonBody(options.Data); } } if (options.FileParameters != null) { foreach (var fileParam in options.FileParameters) { var bytes = ClientUtils.ReadAsBytes(fileParam.Value); var fileStream = fileParam.Value as FileStream; if (fileStream != null) request.Files.Add(FileParameter.Create(fileParam.Key, bytes, System.IO.Path.GetFileName(fileStream.Name))); else request.Files.Add(FileParameter.Create(fileParam.Key, bytes, "no_file_name_provided")); } } if (options.Cookies != null && options.Cookies.Count > 0) { foreach (var cookie in options.Cookies) { request.AddCookie(cookie.Name, cookie.Value); } } return request; } private ApiResponse ToApiResponse(IRestResponse response) { T result = response.Data; string rawContent = response.Content; var transformed = new ApiResponse(response.StatusCode, new Multimap(), result, rawContent) { ErrorText = response.ErrorMessage, Cookies = new List() }; if (response.Headers != null) { foreach (var responseHeader in response.Headers) { transformed.Headers.Add(responseHeader.Name, ClientUtils.ParameterToString(responseHeader.Value)); } } if (response.Cookies != null) { foreach (var responseCookies in response.Cookies) { transformed.Cookies.Add( new Cookie( responseCookies.Name, responseCookies.Value, responseCookies.Path, responseCookies.Domain) ); } } return transformed; } private ApiResponse Exec(RestRequest req, IReadableConfiguration configuration) { RestClient client = new RestClient(_baseUrl); client.ClearHandlers(); var existingDeserializer = req.JsonSerializer as IDeserializer; if (existingDeserializer != null) { client.AddHandler("application/json", () => existingDeserializer); client.AddHandler("text/json", () => existingDeserializer); client.AddHandler("text/x-json", () => existingDeserializer); client.AddHandler("text/javascript", () => existingDeserializer); client.AddHandler("*+json", () => existingDeserializer); } else { var customDeserializer = new CustomJsonCodec(SerializerSettings, configuration); client.AddHandler("application/json", () => customDeserializer); client.AddHandler("text/json", () => customDeserializer); client.AddHandler("text/x-json", () => customDeserializer); client.AddHandler("text/javascript", () => customDeserializer); client.AddHandler("*+json", () => customDeserializer); } var xmlDeserializer = new XmlDeserializer(); client.AddHandler("application/xml", () => xmlDeserializer); client.AddHandler("text/xml", () => xmlDeserializer); client.AddHandler("*+xml", () => xmlDeserializer); client.AddHandler("*", () => xmlDeserializer); client.Timeout = configuration.Timeout; if (configuration.Proxy != null) { client.Proxy = configuration.Proxy; } if (configuration.UserAgent != null) { client.UserAgent = configuration.UserAgent; } if (configuration.ClientCertificates != null) { client.ClientCertificates = configuration.ClientCertificates; } InterceptRequest(req); IRestResponse response; if (RetryConfiguration.RetryPolicy != null) { var policy = RetryConfiguration.RetryPolicy; var policyResult = policy.ExecuteAndCapture(() => client.Execute(req)); response = (policyResult.Outcome == OutcomeType.Successful) ? client.Deserialize(policyResult.Result) : new RestResponse { Request = req, ErrorException = policyResult.FinalException }; } else { response = client.Execute(req); } // if the response type is oneOf/anyOf, call FromJSON to deserialize the data if (typeof(Org.OpenAPITools.Models.AbstractOpenAPISchema).IsAssignableFrom(typeof(T))) { response.Data = (T) typeof(T).GetMethod("FromJson").Invoke(null, new object[] { response.Content }); } else if (typeof(T).Name == "Stream") // for binary response { response.Data = (T)(object)new MemoryStream(response.RawBytes); } InterceptResponse(req, response); var result = ToApiResponse(response); if (response.ErrorMessage != null) { result.ErrorText = response.ErrorMessage; } if (response.Cookies != null && response.Cookies.Count > 0) { if (result.Cookies == null) result.Cookies = new List(); foreach (var restResponseCookie in response.Cookies) { var cookie = new Cookie( restResponseCookie.Name, restResponseCookie.Value, restResponseCookie.Path, restResponseCookie.Domain ) { Comment = restResponseCookie.Comment, CommentUri = restResponseCookie.CommentUri, Discard = restResponseCookie.Discard, Expired = restResponseCookie.Expired, Expires = restResponseCookie.Expires, HttpOnly = restResponseCookie.HttpOnly, Port = restResponseCookie.Port, Secure = restResponseCookie.Secure, Version = restResponseCookie.Version }; result.Cookies.Add(cookie); } } return result; } private async Task> ExecAsync(RestRequest req, IReadableConfiguration configuration, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { RestClient client = new RestClient(_baseUrl); client.ClearHandlers(); var existingDeserializer = req.JsonSerializer as IDeserializer; if (existingDeserializer != null) { client.AddHandler("application/json", () => existingDeserializer); client.AddHandler("text/json", () => existingDeserializer); client.AddHandler("text/x-json", () => existingDeserializer); client.AddHandler("text/javascript", () => existingDeserializer); client.AddHandler("*+json", () => existingDeserializer); } else { var customDeserializer = new CustomJsonCodec(SerializerSettings, configuration); client.AddHandler("application/json", () => customDeserializer); client.AddHandler("text/json", () => customDeserializer); client.AddHandler("text/x-json", () => customDeserializer); client.AddHandler("text/javascript", () => customDeserializer); client.AddHandler("*+json", () => customDeserializer); } var xmlDeserializer = new XmlDeserializer(); client.AddHandler("application/xml", () => xmlDeserializer); client.AddHandler("text/xml", () => xmlDeserializer); client.AddHandler("*+xml", () => xmlDeserializer); client.AddHandler("*", () => xmlDeserializer); client.Timeout = configuration.Timeout; if (configuration.Proxy != null) { client.Proxy = configuration.Proxy; } if (configuration.UserAgent != null) { client.UserAgent = configuration.UserAgent; } if (configuration.ClientCertificates != null) { client.ClientCertificates = configuration.ClientCertificates; } InterceptRequest(req); IRestResponse response; if (RetryConfiguration.AsyncRetryPolicy != null) { var policy = RetryConfiguration.AsyncRetryPolicy; var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(req, ct), cancellationToken).ConfigureAwait(false); response = (policyResult.Outcome == OutcomeType.Successful) ? client.Deserialize(policyResult.Result) : new RestResponse { Request = req, ErrorException = policyResult.FinalException }; } else { response = await client.ExecuteAsync(req, cancellationToken).ConfigureAwait(false); } // if the response type is oneOf/anyOf, call FromJSON to deserialize the data if (typeof(Org.OpenAPITools.Models.AbstractOpenAPISchema).IsAssignableFrom(typeof(T))) { response.Data = (T) typeof(T).GetMethod("FromJson").Invoke(null, new object[] { response.Content }); } else if (typeof(T).Name == "Stream") // for binary response { response.Data = (T)(object)new MemoryStream(response.RawBytes); } InterceptResponse(req, response); var result = ToApiResponse(response); if (response.ErrorMessage != null) { result.ErrorText = response.ErrorMessage; } if (response.Cookies != null && response.Cookies.Count > 0) { if (result.Cookies == null) result.Cookies = new List(); foreach (var restResponseCookie in response.Cookies) { var cookie = new Cookie( restResponseCookie.Name, restResponseCookie.Value, restResponseCookie.Path, restResponseCookie.Domain ) { Comment = restResponseCookie.Comment, CommentUri = restResponseCookie.CommentUri, Discard = restResponseCookie.Discard, Expired = restResponseCookie.Expired, Expires = restResponseCookie.Expires, HttpOnly = restResponseCookie.HttpOnly, Port = restResponseCookie.Port, Secure = restResponseCookie.Secure, Version = restResponseCookie.Version }; result.Cookies.Add(cookie); } } return result; } #region IAsynchronousClient /// /// Make a HTTP GET request (async). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// Token that enables callers to cancel the request. /// A Task containing ApiResponse public Task> GetAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var config = configuration ?? GlobalConfiguration.Instance; return ExecAsync(NewRequest(HttpMethod.Get, path, options, config), config, cancellationToken); } /// /// Make a HTTP POST request (async). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// Token that enables callers to cancel the request. /// A Task containing ApiResponse public Task> PostAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var config = configuration ?? GlobalConfiguration.Instance; return ExecAsync(NewRequest(HttpMethod.Post, path, options, config), config, cancellationToken); } /// /// Make a HTTP PUT request (async). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// Token that enables callers to cancel the request. /// A Task containing ApiResponse public Task> PutAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var config = configuration ?? GlobalConfiguration.Instance; return ExecAsync(NewRequest(HttpMethod.Put, path, options, config), config, cancellationToken); } /// /// Make a HTTP DELETE request (async). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// Token that enables callers to cancel the request. /// A Task containing ApiResponse public Task> DeleteAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var config = configuration ?? GlobalConfiguration.Instance; return ExecAsync(NewRequest(HttpMethod.Delete, path, options, config), config, cancellationToken); } /// /// Make a HTTP HEAD request (async). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// Token that enables callers to cancel the request. /// A Task containing ApiResponse public Task> HeadAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var config = configuration ?? GlobalConfiguration.Instance; return ExecAsync(NewRequest(HttpMethod.Head, path, options, config), config, cancellationToken); } /// /// Make a HTTP OPTION request (async). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// Token that enables callers to cancel the request. /// A Task containing ApiResponse public Task> OptionsAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var config = configuration ?? GlobalConfiguration.Instance; return ExecAsync(NewRequest(HttpMethod.Options, path, options, config), config, cancellationToken); } /// /// Make a HTTP PATCH request (async). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// Token that enables callers to cancel the request. /// A Task containing ApiResponse public Task> PatchAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var config = configuration ?? GlobalConfiguration.Instance; return ExecAsync(NewRequest(HttpMethod.Patch, path, options, config), config, cancellationToken); } #endregion IAsynchronousClient #region ISynchronousClient /// /// Make a HTTP GET request (synchronous). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// A Task containing ApiResponse public ApiResponse Get(string path, RequestOptions options, IReadableConfiguration configuration = null) { var config = configuration ?? GlobalConfiguration.Instance; return Exec(NewRequest(HttpMethod.Get, path, options, config), config); } /// /// Make a HTTP POST request (synchronous). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// A Task containing ApiResponse public ApiResponse Post(string path, RequestOptions options, IReadableConfiguration configuration = null) { var config = configuration ?? GlobalConfiguration.Instance; return Exec(NewRequest(HttpMethod.Post, path, options, config), config); } /// /// Make a HTTP PUT request (synchronous). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// A Task containing ApiResponse public ApiResponse Put(string path, RequestOptions options, IReadableConfiguration configuration = null) { var config = configuration ?? GlobalConfiguration.Instance; return Exec(NewRequest(HttpMethod.Put, path, options, config), config); } /// /// Make a HTTP DELETE request (synchronous). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// A Task containing ApiResponse public ApiResponse Delete(string path, RequestOptions options, IReadableConfiguration configuration = null) { var config = configuration ?? GlobalConfiguration.Instance; return Exec(NewRequest(HttpMethod.Delete, path, options, config), config); } /// /// Make a HTTP HEAD request (synchronous). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// A Task containing ApiResponse public ApiResponse Head(string path, RequestOptions options, IReadableConfiguration configuration = null) { var config = configuration ?? GlobalConfiguration.Instance; return Exec(NewRequest(HttpMethod.Head, path, options, config), config); } /// /// Make a HTTP OPTION request (synchronous). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// A Task containing ApiResponse public ApiResponse Options(string path, RequestOptions options, IReadableConfiguration configuration = null) { var config = configuration ?? GlobalConfiguration.Instance; return Exec(NewRequest(HttpMethod.Options, path, options, config), config); } /// /// Make a HTTP PATCH request (synchronous). /// /// The target path (or resource). /// The additional request options. /// A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method. /// A Task containing ApiResponse public ApiResponse Patch(string path, RequestOptions options, IReadableConfiguration configuration = null) { var config = configuration ?? GlobalConfiguration.Instance; return Exec(NewRequest(HttpMethod.Patch, path, options, config), config); } #endregion ISynchronousClient } }