-Added comments for ApiException.

-Added comments for ApiResponse.
-Added comments for most of the attributes.
-Added comments for RestService.
This commit is contained in:
Laurent Keusch 2021-11-10 14:57:46 +01:00
Родитель ed78b9244b
Коммит 2c23aec026
4 изменённых файлов: 269 добавлений и 8 удалений

Просмотреть файл

@ -6,19 +6,60 @@ using System.Threading.Tasks;
namespace Refit
{
/// <summary>
/// Represents an error that occured while sending an API request.
/// </summary>
[Serializable]
public class ApiException : Exception
{
/// <summary>
/// HTTP response status code.
/// </summary>
public HttpStatusCode StatusCode { get; }
/// <summary>
/// The reason phrase which typically is sent by the server together with the status code.
/// </summary>
public string? ReasonPhrase { get; }
/// <summary>
/// HTTP response headers.
/// </summary>
public HttpResponseHeaders Headers { get; }
/// <summary>
/// The HTTP method used to send the request.
/// </summary>
public HttpMethod HttpMethod { get; }
/// <summary>
/// The <see cref="System.Uri"/> used to send the HTTP request.
/// </summary>
public Uri? Uri => RequestMessage.RequestUri;
/// <summary>
/// The HTTP Request message used to send the request.
/// </summary>
public HttpRequestMessage RequestMessage { get; }
/// <summary>
/// HTTP response content headers as defined in RFC 2616.
/// </summary>
public HttpContentHeaders? ContentHeaders { get; private set; }
/// <summary>
/// HTTP Response content as string.
/// </summary>
public string? Content { get; private set; }
/// <summary>
/// Does the response have content?
/// </summary>
public bool HasContent => !string.IsNullOrWhiteSpace(Content);
/// <summary>
/// Refit settings used to send the request.
/// </summary>
public RefitSettings RefitSettings { get; }
protected ApiException(HttpRequestMessage message, HttpMethod httpMethod, string? content, HttpStatusCode statusCode, string? reasonPhrase, HttpResponseHeaders headers, RefitSettings refitSettings, Exception? innerException = null) :
@ -38,10 +79,24 @@ namespace Refit
Content = content;
}
/// <summary>
/// Get the deserialized response content as nullable <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">Type to deserialize the content to</typeparam>
/// <returns>The response content deserialized as <typeparamref name="T"/></returns>
public async Task<T?> GetContentAsAsync<T>() => HasContent ?
await RefitSettings.ContentSerializer.FromHttpContentAsync<T>(new StringContent(Content!)).ConfigureAwait(false) :
default;
/// <summary>
/// Create an instance of <see cref="ApiException"/>.
/// </summary>
/// <param name="message">The HTTP Request message used to send the request.</param>
/// <param name="httpMethod">The HTTP method used to send the request.</param>
/// <param name="response">The HTTP Response message.</param>
/// <param name="refitSettings">Refit settings used to sent the request.</param>
/// <param name="innerException">Add an inner exception to the <see cref="ApiException"/>.</param>
/// <returns>A newly created <see cref="ApiException"/>.</returns>
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
public static Task<ApiException> Create(HttpRequestMessage message, HttpMethod httpMethod, HttpResponseMessage response, RefitSettings refitSettings, Exception? innerException = null)
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
@ -50,6 +105,16 @@ namespace Refit
return Create(exceptionMessage, message, httpMethod, response, refitSettings, innerException);
}
/// <summary>
/// Create an instance of <see cref="ApiException"/> with a custom exception message.
/// </summary>
/// <param name="exceptionMessage">A custom exception message.</param>
/// <param name="message">The HTTP Request message used to send the request.</param>
/// <param name="httpMethod">The HTTP method used to send the request.</param>
/// <param name="response">The HTTP Response message.</param>
/// <param name="refitSettings">Refit settings used to sent the request.</param>
/// <param name="innerException">Add an inner exception to the <see cref="ApiException"/>.</param>
/// <returns>A newly created <see cref="ApiException"/>.</returns>
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
public static async Task<ApiException> Create(string exceptionMessage, HttpRequestMessage message, HttpMethod httpMethod, HttpResponseMessage response, RefitSettings refitSettings, Exception? innerException = null)
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods

Просмотреть файл

@ -14,11 +14,23 @@ namespace Refit
}
}
/// <summary>
/// Implementation of <see cref="IApiResponse{T}"/> that provides additional functionalities.
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class ApiResponse<T> : IApiResponse<T>
{
readonly HttpResponseMessage response;
bool disposed;
/// <summary>
/// Create an instance of <see cref="ApiResponse{T}"/> with type <typeparamref name="T"/>.
/// </summary>
/// <param name="response">Original HTTP Response message.</param>
/// <param name="content">Response content.</param>
/// <param name="settings">Refit settings used to send the request.</param>
/// <param name="error">The ApiException, if the request failed.</param>
/// <exception cref="ArgumentNullException"></exception>
public ApiResponse(HttpResponseMessage response, T? content, RefitSettings settings, ApiException? error = null)
{
this.response = response ?? throw new ArgumentNullException(nameof(response));
@ -27,16 +39,30 @@ namespace Refit
Settings = settings;
}
/// <summary>
/// Deserialized request content as <typeparamref name="T"/>.
/// </summary>
public T? Content { get; }
public RefitSettings Settings { get; }
/// <summary>
/// Refit settings used to send the request.
/// </summary>
public RefitSettings Settings { get; }
public HttpResponseHeaders Headers => response.Headers;
public HttpContentHeaders? ContentHeaders => response.Content?.Headers;
public bool IsSuccessStatusCode => response.IsSuccessStatusCode;
public string? ReasonPhrase => response.ReasonPhrase;
public HttpRequestMessage? RequestMessage => response.RequestMessage;
public HttpStatusCode StatusCode => response.StatusCode;
public Version Version => response.Version;
public ApiException? Error { get; private set; }
@ -45,6 +71,11 @@ namespace Refit
Dispose(true);
}
/// <summary>
/// Ensures the request was successful by throwing an exception in case of failure
/// </summary>
/// <returns>The current <see cref="ApiResponse{T}"/></returns>
/// <exception cref="ApiException"></exception>
public async Task<ApiResponse<T>> EnsureSuccessStatusCodeAsync()
{
if (!IsSuccessStatusCode)
@ -70,20 +101,58 @@ namespace Refit
}
}
/// <inheritdoc/>
public interface IApiResponse<out T> : IApiResponse
{
/// <summary>
/// Deserialized request content as <typeparamref name="T"/>.
/// </summary>
T? Content { get; }
}
/// <summary>
/// Base interface used to represent an API response.
/// </summary>
public interface IApiResponse : IDisposable
{
/// <summary>
/// HTTP response headers.
/// </summary>
HttpResponseHeaders Headers { get; }
/// <summary>
/// HTTP response content headers as defined in RFC 2616.
/// </summary>
HttpContentHeaders? ContentHeaders { get; }
/// <summary>
/// Indicates whether the request was successful.
/// </summary>
bool IsSuccessStatusCode { get; }
string? ReasonPhrase { get; }
HttpRequestMessage? RequestMessage { get; }
/// <summary>
/// HTTP response status code.
/// </summary>
HttpStatusCode StatusCode { get; }
/// <summary>
/// The reason phrase which typically is sent by the server together with the status code.
/// </summary>
string? ReasonPhrase { get; }
/// <summary>
/// The HTTP Request message which led to this response.
/// </summary>
HttpRequestMessage? RequestMessage { get; }
/// <summary>
/// HTTP Message version.
/// </summary>
Version Version { get; }
/// <summary>
/// The <see cref="ApiException"/> object in case of unsuccessful response.
/// </summary>
ApiException? Error { get; }
}
}

Просмотреть файл

@ -19,6 +19,9 @@ namespace Refit
}
}
/// <summary>
/// Send the request with HTTP method 'GET'.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class GetAttribute : HttpMethodAttribute
{
@ -30,6 +33,9 @@ namespace Refit
}
}
/// <summary>
/// Send the request with HTTP method 'POST'.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class PostAttribute : HttpMethodAttribute
{
@ -41,6 +47,9 @@ namespace Refit
}
}
/// <summary>
/// Send the request with HTTP method 'PUT'.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class PutAttribute : HttpMethodAttribute
{
@ -52,6 +61,9 @@ namespace Refit
}
}
/// <summary>
/// Send the request with HTTP method 'DELETE'.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class DeleteAttribute : HttpMethodAttribute
{
@ -63,6 +75,9 @@ namespace Refit
}
}
/// <summary>
/// Send the request with HTTP method 'PATCH'.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class PatchAttribute : HttpMethodAttribute
{
@ -74,6 +89,9 @@ namespace Refit
}
}
/// <summary>
/// Send the request with HTTP method 'OPTION'.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class OptionsAttribute : HttpMethodAttribute
{
@ -85,6 +103,9 @@ namespace Refit
}
}
/// <summary>
/// Send the request with HTTP method 'HEAD'.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class HeadAttribute : HttpMethodAttribute
{
@ -96,6 +117,12 @@ namespace Refit
}
}
/// <summary>
/// Send the request as multipart.
/// </summary>
/// <remarks>
/// Currently, multipart methods only support the following parameter types: <see cref="string"/>, <see cref="byte"/> array, <see cref="System.IO.Stream"/>, <see cref="System.IO.FileInfo"/>.
/// </remarks>
[AttributeUsage(AttributeTargets.Method)]
public class MultipartAttribute : Attribute
{
@ -132,6 +159,17 @@ namespace Refit
Serialized
}
/// <summary>
/// Set a parameter to be sent as the HTTP request's body.
/// </summary>
/// <remarks>
/// There are four behaviors when sending a parameter as the request body:<br/>
/// - If the type is/implements <see cref="System.IO.Stream"/>, the content will be streamed via <see cref="StreamContent"/>.<br/>
/// - If the type is <see cref="string"/>, it will be used directly as the content unless <c>[Body(BodySerializationMethod.Json)]</c> is set
/// which will send it as a <see cref="StringContent"/>.<br/>
/// - If the parameter has the attribute <c>[Body(BodySerializationMethod.UrlEncoded)]</c>, the content will be URL-encoded.<br/>
/// - For all other types, the object will be serialized using the content serializer specified in the request's <see cref="RefitSettings"/>.
/// </remarks>
[AttributeUsage(AttributeTargets.Parameter)]
public class BodyAttribute : Attribute
{
@ -161,6 +199,9 @@ namespace Refit
public BodySerializationMethod SerializationMethod { get; protected set; } = BodySerializationMethod.Default;
}
/// <summary>
/// Override the key that will be sent in the query string.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public class AliasAsAttribute : Attribute
{
@ -185,7 +226,7 @@ namespace Refit
}
/// <summary>
/// Allows you provide a Dictionary of headers to be added to the request.
/// Allows you to provide a Dictionary of headers to be added to the request.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class HeaderCollectionAttribute : Attribute
@ -193,6 +234,9 @@ namespace Refit
}
/// <summary>
/// Add multiple headers to the request.
/// </summary>
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method)]
public class HeadersAttribute : Attribute
{
@ -204,6 +248,9 @@ namespace Refit
public string[] Headers { get; }
}
/// <summary>
/// Add a header to the request.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class HeaderAttribute : Attribute
{
@ -236,6 +283,12 @@ namespace Refit
public string? Key { get; }
}
/// <summary>
/// Add the Authorize header to the request with the value of the associated parameter.
/// </summary>
/// <remarks>
/// Default authorization scheme: Bearer
/// </remarks>
[AttributeUsage(AttributeTargets.Parameter)]
public class AuthorizeAttribute : Attribute
{
@ -247,8 +300,10 @@ namespace Refit
public string Scheme { get; }
}
/// <summary>
/// Associated value will be added to the request Uri as query-string, using a delimiter to split the values. (default: '.')
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] // Property is to allow for form url encoded data
public class QueryAttribute : Attribute
{
CollectionFormat? collectionFormat;
@ -332,7 +387,6 @@ namespace Refit
}
[AttributeUsage(AttributeTargets.Method)]
public class QueryUriFormatAttribute : Attribute
{
public QueryUriFormatAttribute(UriFormat uriFormat)

Просмотреть файл

@ -8,11 +8,25 @@ namespace Refit
{
static readonly ConcurrentDictionary<Type, Type> TypeMapping = new();
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <typeparam name="T">Interface to create the implementation for.</typeparam>
/// <param name="client">The <see cref="HttpClient"/> the implementation will use to send requests.</param>
/// <param name="builder"><see cref="IRequestBuilder"/> to use to build requests.</param>
/// <returns>An instance that implements <typeparamref name="T"/>.</returns>
public static T For<T>(HttpClient client, IRequestBuilder<T> builder)
{
return (T)For(typeof(T), client, builder);
return (T)For(typeof(T), client, builder);
}
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <typeparam name="T">Interface to create the implementation for.</typeparam>
/// <param name="client">The <see cref="HttpClient"/> the implementation will use to send requests.</param>
/// <param name="settings"><see cref="RefitSettings"/> to use to configure the HttpClient.</param>
/// <returns>An instance that implements <typeparamref name="T"/>.</returns>
public static T For<T>(HttpClient client, RefitSettings? settings)
{
var requestBuilder = RequestBuilder.ForType<T>(settings);
@ -20,8 +34,21 @@ namespace Refit
return For(client, requestBuilder);
}
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <typeparam name="T">Interface to create the implementation for.</typeparam>
/// <param name="client">The <see cref="HttpClient"/> the implementation will use to send requests.</param>
/// <returns>An instance that implements <typeparamref name="T"/>.</returns>
public static T For<T>(HttpClient client) => For<T>(client, (RefitSettings?)null);
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <typeparam name="T">Interface to create the implementation for.</typeparam>
/// <param name="hostUrl">Base address the implementation will use.</param>
/// <param name="settings"><see cref="RefitSettings"/> to use to configure the HttpClient.</param>
/// <returns>An instance that implements <typeparamref name="T"/>.</returns>
public static T For<T>(string hostUrl, RefitSettings? settings)
{
var client = CreateHttpClient(hostUrl, settings);
@ -29,8 +56,21 @@ namespace Refit
return For<T>(client, settings);
}
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <typeparam name="T">Interface to create the implementation for.</typeparam>
/// <param name="hostUrl">Base address the implementation will use.</param>
/// <returns>An instance that implements <typeparamref name="T"/>.</returns>
public static T For<T>(string hostUrl) => For<T>(hostUrl, null);
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <param name="refitInterfaceType">Interface to create the implementation for.</param>
/// <param name="client">The <see cref="HttpClient"/> the implementation will use to send requests.</param>
/// <param name="builder"><see cref="IRequestBuilder"/> to use to build requests.</param>
/// <returns>An instance that implements <paramref name="refitInterfaceType"/>.</returns>
public static object For(Type refitInterfaceType, HttpClient client, IRequestBuilder builder)
{
var generatedType = TypeMapping.GetOrAdd(refitInterfaceType, GetGeneratedType(refitInterfaceType));
@ -38,6 +78,13 @@ namespace Refit
return Activator.CreateInstance(generatedType, client, builder)!;
}
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <param name="refitInterfaceType">Interface to create the implementation for.</param>
/// <param name="client">The <see cref="HttpClient"/> the implementation will use to send requests.</param>
/// <param name="settings"><see cref="RefitSettings"/> to use to configure the HttpClient.</param>
/// <returns>An instance that implements <paramref name="refitInterfaceType"/>.</returns>
public static object For(Type refitInterfaceType, HttpClient client, RefitSettings? settings)
{
var requestBuilder = RequestBuilder.ForType(refitInterfaceType, settings);
@ -45,8 +92,21 @@ namespace Refit
return For(refitInterfaceType, client, requestBuilder);
}
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <param name="refitInterfaceType">Interface to create the implementation for.</param>
/// <param name="client">The <see cref="HttpClient"/> the implementation will use to send requests.</param>
/// <returns>An instance that implements <paramref name="refitInterfaceType"/>.</returns>
public static object For(Type refitInterfaceType, HttpClient client) => For(refitInterfaceType, client, (RefitSettings?)null);
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <param name="refitInterfaceType">Interface to create the implementation for.</param>
/// <param name="hostUrl">Base address the implementation will use.</param>
/// <param name="settings"><see cref="RefitSettings"/> to use to configure the HttpClient.</param>
/// <returns>An instance that implements <paramref name="refitInterfaceType"/>.</returns>
public static object For(Type refitInterfaceType, string hostUrl, RefitSettings? settings)
{
var client = CreateHttpClient(hostUrl, settings);
@ -54,8 +114,21 @@ namespace Refit
return For(refitInterfaceType, client, settings);
}
/// <summary>
/// Generate a Refit implementation of the specified interface.
/// </summary>
/// <param name="refitInterfaceType">Interface to create the implementation for.</param>
/// <param name="hostUrl">Base address the implementation will use.</param>
/// <returns>An instance that implements <paramref name="refitInterfaceType"/>.</returns>
public static object For(Type refitInterfaceType, string hostUrl) => For(refitInterfaceType, hostUrl, null);
/// <summary>
/// Create an <see cref="HttpClient"/> with <paramref name="hostUrl"/> as the base address.
/// </summary>
/// <param name="hostUrl">Base address.</param>
/// <param name="settings"><see cref="RefitSettings"/> to use to configure the HttpClient.</param>
/// <returns>A <see cref="HttpClient"/> with the various parameters provided.</returns>
/// <exception cref="ArgumentException"></exception>
public static HttpClient CreateHttpClient(string hostUrl, RefitSettings? settings)
{
if (string.IsNullOrWhiteSpace(hostUrl))