Skip to content

Commit

Permalink
Make possible to use legacy AddParameter for Body (#1869)
Browse files Browse the repository at this point in the history
* Replacement for #1817

* Added the test from #1817

* Allow also adding properly named body parameters
  • Loading branch information
alexeyzimarev committed Jun 7, 2022
1 parent d3e1334 commit 39e6e7d
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 62 deletions.
2 changes: 1 addition & 1 deletion src/RestSharp/Parameters/Parameter.cs
Expand Up @@ -30,11 +30,11 @@ public abstract record Parameter(string? Name, object? Value, ParameterType Type
public override string ToString() => $"{Name}={Value}";

public static Parameter CreateParameter(string? name, object? value, ParameterType type, bool encode = true)
// ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
=> type switch {
ParameterType.GetOrPost => new GetOrPostParameter(name!, value?.ToString(), encode),
ParameterType.UrlSegment => new UrlSegmentParameter(name!, value?.ToString()!, encode),
ParameterType.HttpHeader => new HeaderParameter(name, value?.ToString()),
ParameterType.RequestBody => new BodyParameter(name, value!, Serializers.ContentType.Plain),
ParameterType.QueryString => new QueryParameter(name!, value?.ToString(), encode),
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
Expand Down
5 changes: 4 additions & 1 deletion src/RestSharp/Request/RestRequest.cs
Expand Up @@ -193,7 +193,10 @@ public RestRequest(Uri resource, Method method = Method.Get)
/// Removes a parameter object from the request parameters
/// </summary>
/// <param name="parameter">Parameter to remove</param>
public void RemoveParameter(Parameter parameter) => Parameters.RemoveParameter(parameter);
public RestRequest RemoveParameter(Parameter parameter) {
Parameters.RemoveParameter(parameter);
return this;
}

internal RestRequest AddFile(FileParameter file) => this.With(x => x._files.Add(file));
}
55 changes: 33 additions & 22 deletions src/RestSharp/Request/RestRequestExtensions.cs
Expand Up @@ -204,7 +204,14 @@ public static RestRequest AddQueryParameter(this RestRequest request, string nam
/// <param name="encode">Encode the value or not, default true</param>
/// <returns></returns>
public static RestRequest AddParameter(this RestRequest request, string? name, object value, ParameterType type, bool encode = true)
=> request.AddParameter(Parameter.CreateParameter(name, value, type, encode));
=> type == ParameterType.RequestBody
? request.AddBodyParameter(name, value)
: request.AddParameter(Parameter.CreateParameter(name, value, type, encode));

static RestRequest AddBodyParameter(this RestRequest request, string? name, object value)
=> name != null && name.Contains("/")
? request.AddBody(value, name)
: request.AddParameter(new BodyParameter(name, value, ContentType.Plain));

/// <summary>
/// Adds or updates request parameter of a given type. It will create a typed parameter instance based on the type argument.
Expand All @@ -218,8 +225,13 @@ public static RestRequest AddParameter(this RestRequest request, string? name, o
/// <param name="type">Enum value specifying what kind of parameter is being added</param>
/// <param name="encode">Encode the value or not, default true</param>
/// <returns></returns>
public static RestRequest AddOrUpdateParameter(this RestRequest request, string name, object value, ParameterType type, bool encode = true)
=> request.AddOrUpdateParameter(Parameter.CreateParameter(name, value, type, encode));
public static RestRequest AddOrUpdateParameter(this RestRequest request, string name, object value, ParameterType type, bool encode = true) {
request.RemoveParameter(name, type);

return type == ParameterType.RequestBody
? request.AddBodyParameter(name, value)
: request.AddOrUpdateParameter(Parameter.CreateParameter(name, value, type, encode));
}

/// <summary>
/// Adds or updates request parameter, given the parameter instance, for example <see cref="QueryParameter"/> or <see cref="UrlSegmentParameter"/>.
Expand All @@ -228,13 +240,12 @@ public static RestRequest AddOrUpdateParameter(this RestRequest request, string
/// <param name="request">Request instance</param>
/// <param name="parameter">Parameter instance</param>
/// <returns></returns>
public static RestRequest AddOrUpdateParameter(this RestRequest request, Parameter parameter) {
var p = request.Parameters.FirstOrDefault(x => x.Name == parameter.Name && x.Type == parameter.Type);

if (p != null) request.RemoveParameter(p);
public static RestRequest AddOrUpdateParameter(this RestRequest request, Parameter parameter)
=> request.RemoveParameter(parameter.Name, parameter.Type).AddParameter(parameter);

request.AddParameter(parameter);
return request;
static RestRequest RemoveParameter(this RestRequest request, string? name, ParameterType type) {
var p = request.Parameters.FirstOrDefault(x => x.Name == name && x.Type == type);
return p != null ? request.RemoveParameter(p) : request;
}

/// <summary>
Expand All @@ -245,8 +256,7 @@ public static RestRequest AddOrUpdateParameter(this RestRequest request, string
/// <param name="parameters">Collection of parameter instances</param>
/// <returns></returns>
public static RestRequest AddOrUpdateParameters(this RestRequest request, IEnumerable<Parameter> parameters) {
foreach (var parameter in parameters)
request.AddOrUpdateParameter(parameter);
foreach (var parameter in parameters) request.AddOrUpdateParameter(parameter);

return request;
}
Expand Down Expand Up @@ -304,15 +314,15 @@ public static RestRequest AddFile(this RestRequest request, string name, byte[]
public static RestRequest AddBody(this RestRequest request, object obj, string? contentType = null) {
if (contentType == null) {
return request.RequestFormat switch {
DataFormat.Json => request.AddJsonBody(obj, contentType ?? ContentType.Json),
DataFormat.Xml => request.AddXmlBody(obj, contentType ?? ContentType.Xml),
DataFormat.Binary => request.AddParameter(new BodyParameter("", obj, contentType ?? ContentType.Binary)),
_ => request.AddParameter(new BodyParameter("", obj.ToString()!, contentType ?? ContentType.Plain))
DataFormat.Json => request.AddJsonBody(obj),
DataFormat.Xml => request.AddXmlBody(obj),
DataFormat.Binary => request.AddParameter(new BodyParameter("", obj, ContentType.Binary)),
_ => request.AddParameter(new BodyParameter("", obj.ToString()!, ContentType.Plain))
};
}

return
obj is string str ? request.AddParameter(new BodyParameter("", str, contentType)) :
obj is string str ? request.AddStringBody(str, contentType) :
obj is byte[] bytes ? request.AddParameter(new BodyParameter("", bytes, contentType, DataFormat.Binary)) :
contentType.Contains("xml") ? request.AddXmlBody(obj, contentType) :
contentType.Contains("json") ? request.AddJsonBody(obj, contentType) :
Expand Down Expand Up @@ -352,7 +362,7 @@ public static RestRequest AddStringBody(this RestRequest request, string body, s
/// <returns></returns>
public static RestRequest AddJsonBody<T>(this RestRequest request, T obj, string contentType = ContentType.Json) where T : class {
request.RequestFormat = DataFormat.Json;
return request.AddParameter(new JsonParameter("", obj, contentType));
return obj is string str ? request.AddStringBody(str, DataFormat.Json) : request.AddParameter(new JsonParameter("", obj, contentType));
}

/// <summary>
Expand All @@ -366,8 +376,10 @@ public static RestRequest AddStringBody(this RestRequest request, string body, s
public static RestRequest AddXmlBody<T>(this RestRequest request, T obj, string contentType = ContentType.Xml, string xmlNamespace = "")
where T : class {
request.RequestFormat = DataFormat.Xml;
request.AddParameter(new XmlParameter("", obj, xmlNamespace, contentType));
return request;

return obj is string str
? request.AddStringBody(str, DataFormat.Xml)
: request.AddParameter(new XmlParameter("", obj, xmlNamespace, contentType));
}

/// <summary>
Expand Down Expand Up @@ -401,7 +413,6 @@ public static RestRequest AddXmlBody<T>(this RestRequest request, T obj, string
.Select(group => group.Key)
.ToList();

if (duplicateKeys.Any())
throw new ArgumentException($"Duplicate header names exist: {string.Join(", ", duplicateKeys)}");
if (duplicateKeys.Any()) throw new ArgumentException($"Duplicate header names exist: {string.Join(", ", duplicateKeys)}");
}
}
}
25 changes: 17 additions & 8 deletions src/RestSharp/RestClient.Async.cs
Expand Up @@ -42,7 +42,7 @@ public partial class RestClient {
response.Request = request;
response.Request.IncreaseNumAttempts();

return Options.ThrowOnAnyError ? ThrowIfError(response) : response;
return Options.ThrowOnAnyError ? response.ThrowIfError() : response;
}

async Task<InternalResponse> ExecuteInternal(RestRequest request, CancellationToken cancellationToken) {
Expand Down Expand Up @@ -130,13 +130,6 @@ record InternalResponse(HttpResponseMessage? ResponseMessage, Uri Url, Exception
bool TimedOut() => timeoutToken.IsCancellationRequested || exception.Message.Contains("HttpClient.Timeout");
}

internal static RestResponse ThrowIfError(RestResponse response) {
var exception = response.GetException();
if (exception != null) throw exception;

return response;
}

static HttpMethod AsHttpMethod(Method method)
=> method switch {
Method.Get => HttpMethod.Get,
Expand All @@ -155,4 +148,20 @@ static HttpMethod AsHttpMethod(Method method)
Method.Search => new HttpMethod("SEARCH"),
_ => throw new ArgumentOutOfRangeException()
};
}

public static class ResponseThrowExtension {
public static RestResponse ThrowIfError(this RestResponse response) {
var exception = response.GetException();
if (exception != null) throw exception;

return response;
}

public static RestResponse<T> ThrowIfError<T>(this RestResponse<T> response) {
var exception = response.GetException();
if (exception != null) throw exception;

return response;
}
}
6 changes: 4 additions & 2 deletions src/RestSharp/RestClientExtensions.Params.cs
Expand Up @@ -40,8 +40,10 @@ public static RestClient AddDefaultParameter(this RestClient client, string name
/// <param name="value">Value of the parameter</param>
/// <param name="type">The type of parameter to add</param>
/// <returns>This request</returns>
public static RestClient AddDefaultParameter(this RestClient client, string name, object value, ParameterType type)
=> client.AddDefaultParameter(Parameter.CreateParameter(name, value, type));
public static RestClient AddDefaultParameter(this RestClient client, string name, object value, ParameterType type) {
if (type == ParameterType.RequestBody) throw new ArgumentException("Default parameter cannot be Body", nameof(type));
return client.AddDefaultParameter(Parameter.CreateParameter(name, value, type));
}

/// <summary>
/// Adds a default header to the RestClient. Used on every request made by this client instance.
Expand Down
42 changes: 14 additions & 28 deletions src/RestSharp/RestClientExtensions.cs
Expand Up @@ -160,14 +160,12 @@ public static Task<RestResponse> ExecutePutAsync(this RestClient client, RestReq
/// <returns></returns>
public static async Task<T?> GetAsync<T>(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteGetAsync<T>(request, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response.Data;
return response.ThrowIfError().Data;
}

public static async Task<RestResponse> GetAsync(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteGetAsync(request, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response;
return response.ThrowIfError();
}

/// <summary>
Expand All @@ -181,17 +179,15 @@ public static Task<RestResponse> ExecutePutAsync(this RestClient client, RestReq
/// <returns></returns>
public static async Task<T?> PostAsync<T>(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecutePostAsync<T>(request, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response.Data;
return response.ThrowIfError().Data;
}

public static RestResponse Post(this RestClient client, RestRequest request)
=> AsyncHelpers.RunSync(() => client.PostAsync(request));

public static async Task<RestResponse> PostAsync(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecutePostAsync(request, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response;
return response.ThrowIfError();
}

/// <summary>
Expand All @@ -205,14 +201,12 @@ public static RestResponse Post(this RestClient client, RestRequest request)
/// <returns></returns>
public static async Task<T?> PutAsync<T>(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync<T>(request, Method.Put, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response.Data;
return response.ThrowIfError().Data;
}

public static async Task<RestResponse> PutAsync(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync(request, Method.Put, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response;
return response.ThrowIfError();
}

/// <summary>
Expand All @@ -226,14 +220,12 @@ public static RestResponse Post(this RestClient client, RestRequest request)
/// <returns></returns>
public static async Task<T?> HeadAsync<T>(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync<T>(request, Method.Head, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response.Data;
return response.ThrowIfError().Data;
}

public static async Task<RestResponse> HeadAsync(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync(request, Method.Head, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response;
return response.ThrowIfError();
}

/// <summary>
Expand All @@ -247,14 +239,12 @@ public static RestResponse Post(this RestClient client, RestRequest request)
/// <returns></returns>
public static async Task<T?> OptionsAsync<T>(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync<T>(request, Method.Options, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response.Data;
return response.ThrowIfError().Data;
}

public static async Task<RestResponse> OptionsAsync(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync(request, Method.Options, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response;
return response.ThrowIfError();
}

/// <summary>
Expand All @@ -268,14 +258,12 @@ public static RestResponse Post(this RestClient client, RestRequest request)
/// <returns></returns>
public static async Task<T?> PatchAsync<T>(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync<T>(request, Method.Patch, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response.Data;
return response.ThrowIfError().Data;
}

public static async Task<RestResponse> PatchAsync(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync(request, Method.Patch, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response;
return response.ThrowIfError();
}

/// <summary>
Expand All @@ -289,14 +277,12 @@ public static RestResponse Post(this RestClient client, RestRequest request)
/// <returns></returns>
public static async Task<T?> DeleteAsync<T>(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync<T>(request, Method.Delete, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response.Data;
return response.ThrowIfError().Data;
}

public static async Task<RestResponse> DeleteAsync(this RestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync(request, Method.Delete, cancellationToken).ConfigureAwait(false);
RestClient.ThrowIfError(response);
return response;
return response.ThrowIfError();
}

/// <summary>
Expand Down
13 changes: 13 additions & 0 deletions test/RestSharp.Tests/RestContentTests.cs
Expand Up @@ -12,4 +12,17 @@ public class RestContentTests {

httpContent.Headers.ContentType!.MediaType.Should().Be(myContentType);
}

[Fact]
public void RestContent_supports_manual_json_body() {
const string myContentType = "application/json";
const string myJsonString = "[]";

var request = new RestRequest("resource").AddParameter(myContentType, myJsonString, ParameterType.RequestBody);
var content = new RequestContent(new RestClient(), request);

var httpContent = content.BuildContent();

httpContent.Headers.ContentType!.MediaType.Should().Be(myContentType);
}
}

0 comments on commit 39e6e7d

Please sign in to comment.