Skip to content

Commit

Permalink
Added remaining overloads (PATCH, HEAD, OPTIONS, DELETE) (#2050)
Browse files Browse the repository at this point in the history
* Added remaining overloads (PATCH, HEAD, OPTIONS, DELETE)
* Fixed sync extensions to use `IRestClient`
  • Loading branch information
alexeyzimarev committed Jul 4, 2023
1 parent 84db183 commit 1370c33
Show file tree
Hide file tree
Showing 20 changed files with 1,056 additions and 809 deletions.
3 changes: 2 additions & 1 deletion benchmarks/RestSharp.Benchmarks/RestSharp.Benchmarks.csproj
Expand Up @@ -9,7 +9,8 @@

<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.18.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\RestSharp.Serializers.NewtonsoftJson\RestSharp.Serializers.NewtonsoftJson.csproj" />
Expand Down
6 changes: 3 additions & 3 deletions gen/SourceGenerator/SourceGenerator.csproj
Expand Up @@ -11,11 +11,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="All"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" PrivateAssets="All"/>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false"/>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
</Project>
File renamed without changes.
66 changes: 32 additions & 34 deletions src/RestSharp/Request/RequestContent.cs
Expand Up @@ -36,47 +36,44 @@ class RequestContent : IDisposable {
_parameters = new RequestParameters(_request.Parameters.Union(_client.DefaultParameters));
}

public HttpContent BuildContent()
{
var postParameters = _parameters.GetContentParameters(_request.Method).ToArray();
public HttpContent BuildContent() {
var postParameters = _parameters.GetContentParameters(_request.Method).ToArray();
var postParametersExists = postParameters.Length > 0;
var bodyParametersExists = _request.TryGetBodyParameter(out var bodyParameter);
var filesExists = _request.Files.Any();
var filesExists = _request.Files.Any();

if (filesExists)
AddFiles();
if (_request.HasFiles() ||
BodyShouldBeMultipartForm(bodyParameter) ||
filesExists ||
_request.AlwaysMultipartFormData) {
Content = CreateMultipartFormDataContent();
}

if (filesExists) AddFiles();

if (bodyParametersExists)
AddBody(postParametersExists, bodyParameter!);
if (bodyParametersExists) AddBody(postParametersExists, bodyParameter!);

if (postParametersExists)
AddPostParameters(postParameters);
if (postParametersExists) AddPostParameters(postParameters);

AddHeaders();

return Content!;
}

void AddFiles()
{
// File uploading without multipart/form-data
if (_request.AlwaysSingleFileAsContent && _request.Files.Count == 1)
{
var fileParameter = _request.Files.First();
Content = ToStreamContent(fileParameter);
return;
}

var mpContent = new MultipartFormDataContent(GetOrSetFormBoundary());

foreach (var fileParameter in _request.Files)
mpContent.Add(ToStreamContent(fileParameter));

Content = mpContent;
}

StreamContent ToStreamContent(FileParameter fileParameter)
{

void AddFiles() {
// File uploading without multipart/form-data
if (_request is { AlwaysSingleFileAsContent: true, Files.Count: 1 }) {
var fileParameter = _request.Files.First();
Content?.Dispose();
Content = ToStreamContent(fileParameter);
return;
}

var mpContent = Content as MultipartFormDataContent;
foreach (var fileParameter in _request.Files) mpContent!.Add(ToStreamContent(fileParameter));
}

StreamContent ToStreamContent(FileParameter fileParameter) {
var stream = fileParameter.GetFile();
_streams.Add(stream);
var streamContent = new StreamContent(stream);
Expand Down Expand Up @@ -123,7 +120,9 @@ StreamContent ToStreamContent(FileParameter fileParameter)
}
}

static bool BodyShouldBeMultipartForm(BodyParameter bodyParameter) {
static bool BodyShouldBeMultipartForm(BodyParameter? bodyParameter) {
if (bodyParameter == null) return false;

var bodyContentType = bodyParameter.ContentType.OrValue(bodyParameter.Name);
return bodyParameter.Name.IsNotEmpty() && bodyParameter.Name != bodyContentType;
}
Expand All @@ -139,8 +138,7 @@ StreamContent ToStreamContent(FileParameter fileParameter)
return mpContent;
}

void AddBody(bool hasPostParameters, BodyParameter bodyParameter)
{
void AddBody(bool hasPostParameters, BodyParameter bodyParameter) {
var bodyContent = Serialize(bodyParameter);

// we need to send the body
Expand Down
5 changes: 4 additions & 1 deletion src/RestSharp/RestClient.Async.cs
Expand Up @@ -79,7 +79,10 @@ public partial class RestClient {

request.ValidateParameters();
var authenticator = request.Authenticator ?? Options.Authenticator;
if (authenticator != null) await authenticator.Authenticate(this, request).ConfigureAwait(false);

if (authenticator != null) {
await authenticator.Authenticate(this, request).ConfigureAwait(false);
}

using var requestContent = new RequestContent(this, request);

Expand Down
37 changes: 0 additions & 37 deletions src/RestSharp/RestClient.Extensions.Config.cs

This file was deleted.

106 changes: 106 additions & 0 deletions src/RestSharp/RestClient.Extensions.Delete.cs
@@ -0,0 +1,106 @@
// Copyright (c) .NET Foundation and Contributors
//
// Licensed 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.
//

namespace RestSharp;

public static partial class RestClientExtensions {
/// <summary>
/// Executes a DELETE-style request asynchronously, authenticating if needed
/// </summary>
/// <param name="client"></param>
/// <param name="request">Request to be executed</param>
/// <param name="cancellationToken">Cancellation token</param>
public static Task<RestResponse> ExecuteDeleteAsync(this IRestClient client, RestRequest request, CancellationToken cancellationToken = default)
=> client.ExecuteAsync(request, Method.Delete, cancellationToken);

/// <summary>
/// Executes a DELETE-style synchronously, authenticating if needed
/// </summary>
/// <param name="client"></param>
/// <param name="request">Request to be executed</param>
public static RestResponse ExecuteDelete(this IRestClient client, RestRequest request)
=> AsyncHelpers.RunSync(() => client.ExecuteAsync(request, Method.Delete));

/// <summary>
/// Executes a DELETE-style request asynchronously, authenticating if needed.
/// The response content then gets deserialized to T.
/// </summary>
/// <typeparam name="T">Target deserialization type</typeparam>
/// <param name="client"></param>
/// <param name="request">Request to be executed</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns>Deserialized response content</returns>
public static Task<RestResponse<T>> ExecuteDeleteAsync<T>(
this IRestClient client,
RestRequest request,
CancellationToken cancellationToken = default
)
=> client.ExecuteAsync<T>(request, Method.Delete, cancellationToken);

/// <summary>
/// Executes a DELETE-style request synchronously, authenticating if needed.
/// The response content then gets deserialized to T.
/// </summary>
/// <typeparam name="T">Target deserialization type</typeparam>
/// <param name="client"></param>
/// <param name="request">Request to be executed</param>
/// <returns>Deserialized response content</returns>
public static RestResponse<T> ExecuteDelete<T>(this IRestClient client, RestRequest request)
=> AsyncHelpers.RunSync(() => client.ExecuteAsync<T>(request, Method.Delete));

/// <summary>
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
/// The response data is deserialized to the Data property of the returned response object.
/// </summary>
/// <param name="client">RestClient instance</param>
/// <param name="request">The request</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <typeparam name="T">Expected result type</typeparam>
/// <returns></returns>
public static async Task<T?> DeleteAsync<T>(this IRestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync<T>(request, Method.Delete, cancellationToken).ConfigureAwait(false);
return response.ThrowIfError().Data;
}

/// <summary>
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
/// The response data is deserialized to the Data property of the returned response object.
/// </summary>
/// <param name="client">RestClient instance</param>
/// <param name="request">The request</param>
/// <typeparam name="T">Expected result type</typeparam>
/// <returns></returns>
public static T? Delete<T>(this IRestClient client, RestRequest request) => AsyncHelpers.RunSync(() => client.DeleteAsync<T>(request));

/// <summary>
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
/// </summary>
/// <param name="client">RestClient instance</param>
/// <param name="request">The request</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns></returns>
public static async Task<RestResponse> DeleteAsync(this IRestClient client, RestRequest request, CancellationToken cancellationToken = default) {
var response = await client.ExecuteAsync(request, Method.Delete, cancellationToken).ConfigureAwait(false);
return response.ThrowIfError();
}

/// <summary>
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
/// </summary>
/// <param name="client">RestClient instance</param>
/// <param name="request">The request</param>
/// <returns></returns>
public static RestResponse Delete(this IRestClient client, RestRequest request) => AsyncHelpers.RunSync(() => client.DeleteAsync(request));
}

0 comments on commit 1370c33

Please sign in to comment.