/* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
using System;
using System.Runtime.Serialization;
using System.Text;
using OpenSearch.Net;
namespace OpenSearch.Client
{
///
/// A response from OpenSearch
///
public interface IResponse : IOpenSearchResponse
{
///
/// A lazily computed, human readable string representation of what happened during a request for both successful and
/// failed requests. Useful whilst developing or to log when is false on responses.
///
[IgnoreDataMember]
string DebugInformation { get; }
///
/// Checks if a response is functionally valid or not.
/// This is a OpenSearch.Client abstraction to have a single property to check whether there was something wrong with a request.
///
/// For instance, an OpenSearch bulk response always returns 200 and individual bulk items may fail,
/// will be false in that case.
///
///
/// You can also configure the client to always throw an using
/// if the response is not valid
///
///
[IgnoreDataMember]
bool IsValid { get; }
///
/// If the request resulted in an exception on the client side this will hold the exception that was thrown.
///
/// This property is a shortcut to 's
/// and
/// is possibly set when is false depending on the cause of the error
///
///
/// You can also configure the client to always throw an using
/// if the response is not valid
///
///
[IgnoreDataMember]
Exception OriginalException { get; }
///
/// If the response results in an error on OpenSearch's side an error
element will be returned, this is
/// mapped to
/// in OpenSearch.Client.
/// Possibly set when is false, depending on the cause of the error
///
/// You can also configure the client to always throw an using
/// if the response is not valid
///
///
[IgnoreDataMember]
ServerError ServerError { get; }
}
public abstract class ResponseBase : IResponse
{
private Error _error;
private IApiCallDetails _originalApiCall;
private ServerError _serverError;
private int? _statusCode;
/// Returns useful information about the request(s) that were part of this API call.
public virtual IApiCallDetails ApiCall => _originalApiCall;
///
public string DebugInformation
{
get
{
var sb = new StringBuilder();
sb.Append($"{(!IsValid ? "Inv" : "V")}alid OpenSearch.Client response built from a ");
sb.AppendLine(ApiCall?.ToString().ToCamelCase() ?? "null ApiCall which is highly exceptional, please open a bug if you see this");
if (!IsValid) DebugIsValid(sb);
if (ApiCall != null) ResponseStatics.DebugInformationBuilder(ApiCall, sb);
return sb.ToString();
}
}
///
public virtual bool IsValid
{
get
{
var statusCode = ApiCall?.HttpStatusCode;
if (statusCode == 404) return false;
return (ApiCall?.Success ?? false) && ServerError == null;
}}
///
public Exception OriginalException => ApiCall?.OriginalException;
///
public ServerError ServerError
{
get
{
if (_serverError != null) return _serverError;
if (_error == null) return null;
_serverError = new ServerError(_error, _statusCode);
return _serverError;
}
}
[DataMember(Name = "error")]
internal Error Error
{
get => _error;
set
{
_error = value;
_serverError = null;
}
}
[DataMember(Name = "status")]
internal int? StatusCode
{
get => _statusCode;
set
{
_statusCode = value;
_serverError = null;
}
}
[IgnoreDataMember]
IApiCallDetails IOpenSearchResponse.ApiCall
{
get => _originalApiCall;
set => _originalApiCall = value;
}
bool IOpenSearchResponse.TryGetServerErrorReason(out string reason)
{
reason = ServerError?.Error?.ToString();
return !reason.IsNullOrEmpty();
}
/// Subclasses can override this to provide more information on why a call is not valid.
protected virtual void DebugIsValid(StringBuilder sb) { }
public override string ToString() => $"{(!IsValid ? "Inv" : "V")}alid OpenSearch.Client response built from a {ApiCall?.ToString().ToCamelCase()}";
}
}