Skip to content

Commit

Permalink
Merge pull request #176 from hassanhabib/users/hassanhabib/controller…
Browse files Browse the repository at this point in the history
…s-custome-http

CONTROLLERS: Support Custom Http Methods (Client & Server)
  • Loading branch information
hassanhabib authored May 20, 2024
2 parents 2205ea0 + 9972981 commit bc97e43
Show file tree
Hide file tree
Showing 17 changed files with 814 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// ----------------------------------------------------------------------------------
// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers
// ----------------------------------------------------------------------------------

using System;
using System.Threading.Tasks;
using FluentAssertions;
using Newtonsoft.Json;
using RESTFulSense.Tests.Acceptance.Models;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using Xunit;

namespace RESTFulSense.Tests.Acceptance.Tests
{
public partial class RestfulApiClientTests
{

[Fact]
private void ShouldSendContentWithNoResponseAndDeserializeContent()
{
// given
TEntity randomTEntity = GetRandomTEntity();
TEntity inputTEntity = randomTEntity;
TEntity expectedTEntity = inputTEntity;
string mediaType = "application/json";
bool ignoreDefaultValues = false;
string randomHttpMethodName = GetRandomHttpMethodName();

this.wiremockServer.Given(Request.Create()
.WithPath(relativeUrl)
.UsingMethod(randomHttpMethodName))
.RespondWith(Response.Create()
.WithStatusCode(200));

// when
Action actualResponseResult = async () =>
await this.restfulApiClient.SendHttpRequestAsync<TEntity>(
method: randomHttpMethodName,
relativeUrl: relativeUrl,
content: inputTEntity,
mediaType: mediaType,
ignoreDefaultValues: ignoreDefaultValues,
serializationFunction: SerializationContentFunction);

// then
actualResponseResult.Should().NotBeNull();
}

[Fact]
private async Task ShouldSendContentWithTContentReturnsTResultAsync()
{
// given
TEntity randomTEntity = GetRandomTEntity();
TEntity inputTEntity = randomTEntity;
TEntity expectedTEntity = inputTEntity;
string mediaType = "text/json";
bool ignoreDefaultValues = false;
string randomHttpMethodName = GetRandomHttpMethodName();

string expectedBody =
JsonConvert.SerializeObject(randomTEntity);

this.wiremockServer.Given(
Request.Create()
.WithPath(relativeUrl)
.UsingMethod(randomHttpMethodName))
.RespondWith(
Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", mediaType)
.WithBody(expectedBody));

// when
TEntity actualTEntity =
await this.restfulApiClient.SendHttpRequestAsync<TEntity, TEntity>(
method: randomHttpMethodName,
relativeUrl: relativeUrl,
content: inputTEntity,
mediaType: mediaType,
ignoreDefaultValues: ignoreDefaultValues,
serializationFunction: SerializationContentFunction,
deserializationFunction: DeserializationContentFunction);

// then
actualTEntity.Should().BeEquivalentTo(expectedTEntity);
}
}
}
3 changes: 3 additions & 0 deletions RESTFulSense.Tests.Acceptance/Tests/RestfulApiClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ await Task.FromResult(JsonSerializer.Deserialize<TEntity>(
private static TEntity GetRandomTEntity() =>
CreateTEntityFiller(GetTestDateTimeOffset()).Create();

private static string GetRandomHttpMethodName() =>
new MnemonicString().GetValue();

private static DateTimeOffset GetTestDateTimeOffset() =>
new DateTimeOffset(DateTime.Now);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// ----------------------------------------------------------------------------------
// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers
// ----------------------------------------------------------------------------------

using System;
using System.Threading.Tasks;
using FluentAssertions;
using Newtonsoft.Json;
using RESTFulSense.Tests.Acceptance.Models;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using Xunit;

namespace RESTFulSense.Tests.Acceptance.Tests
{
public partial class RestfulSenseApiFactoryTests
{
[Fact]
private void ShouldSendContentWithNoResponseAndDeserializeContent()
{
// given
TEntity randomTEntity = GetRandomTEntity();
TEntity inputTEntity = randomTEntity;
TEntity expectedTEntity = inputTEntity;
string mediaType = "application/json";
bool ignoreDefaultValues = false;
string randomHttpMethodName = GetRandomHttpMethodName();

this.wiremockServer.Given(Request.Create()
.WithPath(relativeUrl)
.UsingMethod(randomHttpMethodName))
.RespondWith(Response.Create()
.WithStatusCode(200));

// when
Action actualResponseResult = async () =>
await this.factoryClient.SendHttpRequestAsync<TEntity>(
method: randomHttpMethodName,
relativeUrl: relativeUrl,
content: inputTEntity,
mediaType: mediaType,
ignoreDefaultValues: ignoreDefaultValues,
serializationFunction: SerializationContentFunction);

// then
actualResponseResult.Should().NotBeNull();
}

[Fact]
private async Task ShouldSendContentWithTContentReturnsTResultAsync()
{
// given
TEntity randomTEntity = GetRandomTEntity();
TEntity inputTEntity = randomTEntity;
TEntity expectedTEntity = inputTEntity;
string mediaType = "text/json";
bool ignoreDefaultValues = false;
string randomHttpMethodName = GetRandomHttpMethodName();

string expectedBody =
JsonConvert.SerializeObject(randomTEntity);

this.wiremockServer.Given(
Request.Create()
.WithPath(relativeUrl)
.UsingMethod(randomHttpMethodName))
.RespondWith(
Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", mediaType)
.WithBody(expectedBody));

// when
TEntity actualTEntity =
await this.factoryClient.SendHttpRequestAsync<TEntity, TEntity>(
method: randomHttpMethodName,
relativeUrl: relativeUrl,
content: inputTEntity,
mediaType: mediaType,
ignoreDefaultValues: ignoreDefaultValues,
serializationFunction: SerializationContentFunction,
deserializationFunction: ContentDeserializationFunction);

// then
actualTEntity.Should().BeEquivalentTo(expectedTEntity);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ await Task.FromResult(JsonSerializer.Deserialize<TEntity>(
private static TEntity GetRandomTEntity() =>
CreateTEntityFiller(GetTestDateTimeOffset()).Create();

private static string GetRandomHttpMethodName() =>
new MnemonicString().GetValue();

private static DateTimeOffset GetTestDateTimeOffset() =>
new DateTimeOffset(DateTime.Now);

Expand Down
24 changes: 24 additions & 0 deletions RESTFulSense.WebAssembly/Clients/IRESTFulApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,29 @@ ValueTask<T> DeleteContentAsync<T>(

ValueTask<HttpResponseMessage> ExecuteHttpCallAsync(
Task<HttpResponseMessage> function);

ValueTask<T> SendHttpRequestAsync<T>(
string method,
string relativeUrl,
CancellationToken cancellationToken,
Func<string, ValueTask<T>> deserailizationFunction = null);

ValueTask<T> SendHttpRequestAsync<T>(
string method,
string relativeUrl,
T content,
string mediaType = "text/json",
bool ignoreDefaultValues = false,
Func<T, ValueTask<string>> serializationFunction = null,
Func<string, ValueTask<T>> deserializationFunction = null);

ValueTask<TResult> SendHttpRequestAsync<TContent, TResult>(
string method,
string relativeUrl,
TContent content,
string mediaType = "text/json",
bool ignoreDefaultValues = false,
Func<TContent, ValueTask<string>> serializationFunction = null,
Func<string, ValueTask<TResult>> deserializationFunction = null);
}
}
24 changes: 24 additions & 0 deletions RESTFulSense.WebAssembly/Clients/IRESTFulApiFactoryClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,29 @@ ValueTask<T> DeleteContentAsync<T>(

ValueTask<HttpResponseMessage> ExecuteHttpCallAsync(
Task<HttpResponseMessage> function);

ValueTask<T> SendHttpRequestAsync<T>(
string method,
string relativeUrl,
CancellationToken cancellationToken,
Func<string, ValueTask<T>> deserailizationFunction = null);

ValueTask<T> SendHttpRequestAsync<T>(
string method,
string relativeUrl,
T content,
string mediaType = "text/json",
bool ignoreDefaultValues = false,
Func<T, ValueTask<string>> serializationFunction = null,
Func<string, ValueTask<T>> deserializationFunction = null);

ValueTask<TResult> SendHttpRequestAsync<TContent, TResult>(
string method,
string relativeUrl,
TContent content,
string mediaType = "text/json",
bool ignoreDefaultValues = false,
Func<TContent, ValueTask<string>> serializationFunction = null,
Func<string, ValueTask<TResult>> deserializationFunction = null);
}
}
85 changes: 85 additions & 0 deletions RESTFulSense.WebAssembly/Clients/RESTFulApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,5 +425,90 @@ public async ValueTask<HttpResponseMessage> ExecuteHttpCallAsync(

return httpResponseMessage;
}

public async ValueTask<T> SendHttpRequestAsync<T>(
string method,
string relativeUrl,
CancellationToken cancellationToken,
Func<string, ValueTask<T>> deserializationFunction = null)
{
var httpMethod = new HttpMethod(method);

HttpResponseMessage responseMessage =
await SendAsync(
request: new HttpRequestMessage(httpMethod, relativeUrl),
cancellationToken: cancellationToken);

await ValidationService.ValidateHttpResponseAsync(responseMessage);

return await DeserializeResponseContent<T>(
responseMessage, deserializationFunction);
}

public async ValueTask<T> SendHttpRequestAsync<T>(
string method,
string relativeUrl,
T content,
string mediaType = "text/json",
bool ignoreDefaultValues = false,
Func<T, ValueTask<string>> serializationFunction = null,
Func<string, ValueTask<T>> deserializationFunction = null)
{
HttpContent contentString =
await ConvertToHttpContent(
content,
mediaType,
ignoreDefaultValues,
serializationFunction);

var httpMethod = new HttpMethod(method);

HttpResponseMessage responseMessage =
await SendAsync(
request: new HttpRequestMessage
{
Method = httpMethod,
RequestUri = new Uri(relativeUrl),
Content = contentString
});

await ValidationService.ValidateHttpResponseAsync(responseMessage);

return await DeserializeResponseContent<T>(
responseMessage,
deserializationFunction);
}

public async ValueTask<TResult> SendHttpRequestAsync<TContent, TResult>(
string method,
string relativeUrl,
TContent content,
string mediaType = "text/json",
bool ignoreDefaultValues = false,
Func<TContent, ValueTask<string>> serializationFunction = null,
Func<string, ValueTask<TResult>> deserializationFunction = null)
{
HttpContent contentString =
await ConvertToHttpContent(
content,
mediaType,
ignoreDefaultValues,
serializationFunction);

var httpMethod = new HttpMethod(method);

HttpResponseMessage responseMessage =
await SendAsync(
request: new HttpRequestMessage(httpMethod, relativeUrl)
{
Content = contentString
});

await ValidationService.ValidateHttpResponseAsync(responseMessage);

return await DeserializeResponseContent(
responseMessage,
deserializationFunction);
}
}
}
Loading

0 comments on commit bc97e43

Please # to comment.