Skip to content

Commit f9aaa5c

Browse files
committed
feat(api): refactor to remove flurl apiclient dependency
1 parent bbf85d8 commit f9aaa5c

File tree

9 files changed

+79
-29
lines changed

9 files changed

+79
-29
lines changed

src/Appy.Configuration.1Password/Internals/DependencyRegistration.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ internal static IServiceCollection AddOnePasswordToolDependencies(
5353
services
5454
.AddSingleton<OnePasswordApiClientSettings>()
5555
.AddSingleton<IOnePasswordApiClientFactory>(sp => new OnePasswordApiClientFactory(
56-
sp.GetRequiredService<IHttpClientFactory>()))
56+
sp.GetRequiredService<IHttpClientFactory>(),
57+
sp.GetRequiredService<IAppyJsonSerializer>()))
5758
.AddIfElse(useLocalTool,
5859
s => s.AddSingleton<IOnePasswordTool, OnePasswordLocalTool>(),
5960
s => s.AddSingleton<IOnePasswordTool, OnePasswordRemoteTool>());
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
using System;
22
using System.Net.Http;
3+
using Appy.Configuration.Serializers;
34
using Appy.Infrastructure.OnePassword.ApiClient;
45

56
namespace Appy.Configuration.OnePassword.Internals
67
{
78
public class OnePasswordApiClientFactory: IOnePasswordApiClientFactory
89
{
910
readonly IHttpClientFactory _httpClientFactory;
11+
readonly IAppyJsonSerializer _jsonSerializer;
1012

11-
public OnePasswordApiClientFactory(IHttpClientFactory httpClientFactory)
13+
public OnePasswordApiClientFactory(
14+
IHttpClientFactory httpClientFactory,
15+
IAppyJsonSerializer jsonSerializer)
1216
{
1317
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
18+
_jsonSerializer = jsonSerializer ?? throw new ArgumentNullException(nameof(jsonSerializer));
1419
}
1520

1621
public OnePasswordApiClient Create()
1722
{
1823
var httpClient = _httpClientFactory.CreateClient(nameof(OnePasswordApiClient));
19-
20-
return new OnePasswordApiClient(httpClient);
24+
25+
return new OnePasswordApiClient(httpClient, _jsonSerializer);
2126
}
2227
}
2328
}
Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,54 @@
1+
using System;
12
using System.Net.Http;
3+
using System.Text;
24
using System.Threading;
35
using System.Threading.Tasks;
6+
using Appy.Configuration.Serializers;
47
using Appy.Infrastructure.OnePassword.Queries;
5-
using Flurl.Http;
68

79
namespace Appy.Infrastructure.OnePassword.ApiClient
810
{
911
public class OnePasswordApiClient
1012
{
11-
readonly FlurlClient _client;
13+
readonly HttpClient _httpClient;
14+
readonly IAppyJsonSerializer _jsonSerializer;
1215

13-
public OnePasswordApiClient(HttpClient httpClient)
16+
public OnePasswordApiClient(
17+
HttpClient httpClient,
18+
IAppyJsonSerializer jsonSerializer)
1419
{
15-
_client = new FlurlClient(httpClient);
20+
_httpClient = httpClient;
21+
_jsonSerializer = jsonSerializer;
1622
}
1723

18-
public virtual Task<Response<GetOnePasswordNoteQueryResult>> Execute(GetOnePasswordNoteQuery query, CancellationToken cancellationToken = default(CancellationToken))
24+
public virtual Task<Response<GetOnePasswordNoteQueryResult>> Execute(GetOnePasswordNoteQuery query, CancellationToken cancellationToken = default)
1925
{
20-
return _client
21-
.Request("queries/getOnePasswordNote")
22-
.PostJsonAsync(query, cancellationToken)
23-
.ReceiveJson<Response<GetOnePasswordNoteQueryResult>>();
26+
return PostJsonAsync<GetOnePasswordNoteQueryResult>("queries/getOnePasswordNote", query, cancellationToken);
27+
}
28+
29+
async Task<Response<TResponse>> PostJsonAsync<TResponse>(string url, object request, CancellationToken cancellationToken)
30+
{
31+
var content = _jsonSerializer.Serialize(request);
32+
33+
var requestMessage = new HttpRequestMessage
34+
{
35+
Method = HttpMethod.Post,
36+
RequestUri = new Uri(_httpClient.BaseAddress, url),
37+
Content = new StringContent(content, Encoding.UTF8, "application/json")
38+
};
39+
40+
var rawResponse = await _httpClient.SendAsync(requestMessage, cancellationToken);
41+
42+
var json = await rawResponse.Content.ReadAsStringAsync();
43+
44+
var response = _jsonSerializer.Deserialize<Response<TResponse>>(json);
45+
46+
if (rawResponse.IsSuccessStatusCode)
47+
return response;
48+
49+
throw new OnePasswordApiClientException(
50+
statusCode: (int)rawResponse.StatusCode,
51+
response);
2452
}
2553
}
2654
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace Appy.Infrastructure.OnePassword.ApiClient
4+
{
5+
public class OnePasswordApiClientException : Exception
6+
{
7+
public Response Response { get; }
8+
9+
public int? StatusCode { get; }
10+
11+
public OnePasswordApiClientException(int? statusCode, Response response)
12+
{
13+
StatusCode = statusCode;
14+
Response = response;
15+
}
16+
}
17+
}

src/Appy.Infrastructure.1Password/Appy.Infrastructure.1Password.csproj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@
1313
</ItemGroup>
1414

1515
<ItemGroup>
16-
<PackageReference Include="Flurl" Version="$(FlurlPackageVersion)" />
17-
<PackageReference Include="Flurl.Http" Version="$(FlurlPackageVersion)" />
1816
<PackageReference Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" Version="$(TunnelVisionLabsRefAssemblyAnnotatorPackageVersion)" PrivateAssets="all" />
19-
<PackageDownload Include="Microsoft.NETCore.App.Ref" Version="[$(AnnotatedReferenceAssemblyVersion)]" />
17+
<PackageDownload Include="Microsoft.NETCore.App.Ref" Version="[$(AnnotatedReferenceAssemblyVersion)]" />
2018
<PackageReference Include="Nullable" Version="$(NullablePackageVersion)">
2119
<PrivateAssets>all</PrivateAssets>
2220
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

src/Appy.Infrastructure.1Password/Tooling/RemoteToolExtensions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Threading.Tasks;
33
using Appy.Infrastructure.OnePassword.ApiClient;
4-
using Flurl.Http;
54

65
namespace Appy.Infrastructure.OnePassword.Tooling
76
{
@@ -24,9 +23,9 @@ internal static async Task<T> UnWrap<T>(this Task<Response<T>> task)
2423

2524
message = response?.Message!;
2625
}
27-
catch (FlurlHttpException httpException)
26+
catch (OnePasswordApiClientException httpException)
2827
{
29-
var response = await httpException.GetResponseJsonAsync<Response>();
28+
var response = httpException.Response;
3029
message = response?.Message;
3130
exceptionResult = response;
3231
innerException = httpException;
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
using System.Net.Http;
2+
using Appy.Configuration.Serializers;
23
using Appy.Infrastructure.OnePassword.ApiClient;
34

45
namespace Appy.Tool.OnePassword.Tests.Api.Fixtures
56
{
67
public class OnePasswordApiTestClientFactory: IOnePasswordApiClientFactory
78
{
8-
private readonly HttpClient _httpClient;
9+
readonly HttpClient _httpClient;
10+
readonly IAppyJsonSerializer _jsonSerializer;
911

10-
public OnePasswordApiTestClientFactory(HttpClient httpClient)
12+
public OnePasswordApiTestClientFactory(HttpClient httpClient, IAppyJsonSerializer jsonSerializer)
1113
{
1214
_httpClient = httpClient;
15+
_jsonSerializer = jsonSerializer;
1316
}
1417

1518
public OnePasswordApiClient Create()
1619
{
17-
return new OnePasswordApiClient(_httpClient);
20+
return new OnePasswordApiClient(_httpClient, _jsonSerializer);
1821
}
1922
}
2023
}

src/Appy.Tool.1Password.Tests/Api/OnePasswordApiToolEndpointsTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Threading.Tasks;
55
using Appy.Configuration;
66
using Appy.Configuration.Common;
7+
using Appy.Configuration.Serializers;
78
using Appy.Configuration.Validation;
89
using Appy.Infrastructure.OnePassword.ApiClient;
910
using Appy.Infrastructure.OnePassword.Model;
@@ -12,7 +13,6 @@
1213
using Appy.Infrastructure.OnePassword.Tooling;
1314
using Appy.Tool.OnePassword.Tests.Api.Fixtures;
1415
using FluentAssertions;
15-
using Flurl.Http;
1616
using Microsoft.Extensions.DependencyInjection;
1717
using Xunit;
1818
using Xunit.Abstractions;
@@ -68,7 +68,7 @@ public async Task ShouldBeUnsuccessfulResponseWithValidationInfo()
6868
Func<Task> act = async () => await fixture.RemoteTool.Execute(query);
6969

7070
var assertion = await act.Should().ThrowAsync<OnePasswordToolException>();
71-
assertion.WithInnerException<FlurlHttpException>();
71+
assertion.WithInnerException<OnePasswordApiClientException>();
7272

7373
var response = assertion.And.GetContentAs<Response>();
7474
response.Success.Should().BeFalse();
@@ -101,7 +101,7 @@ public async Task ShouldBeUnsuccessfulResponseWithLocalExceptionInfo()
101101
Func<Task> act = async () => await fixture.RemoteTool.Execute(query);
102102

103103
var assertion = await act.Should().ThrowAsync<OnePasswordToolException>();
104-
assertion.WithInnerException<FlurlHttpException>();
104+
assertion.WithInnerException<OnePasswordApiClientException>();
105105

106106
var response = assertion.And.GetContentAs<Response>();
107107
response.Success.Should().BeFalse();
@@ -130,7 +130,7 @@ public async Task ShouldBeUnsuccessfulResponseWithInternalErrorMessage()
130130
Func<Task> act = async () => await fixture.RemoteTool.Execute(query);
131131

132132
var assertion = await act.Should().ThrowAsync<OnePasswordToolException>();
133-
assertion.WithInnerException<FlurlHttpException>();
133+
assertion.WithInnerException<OnePasswordApiClientException>();
134134

135135
var response = assertion.And.GetContentAs<Response>();
136136
response.Success.Should().BeFalse();
@@ -155,11 +155,11 @@ public Fixture(OnePasswordApiTestFixture apiTestFixture)
155155
_apiTestFixture = apiTestFixture;
156156
_apiTestFixture.ServicesConfiguration = services => services
157157
.ReplaceSingleton<IOnePasswordTool>(sp =>
158-
LocalTool.Object.WithValidation(sp.GetService<IValidator>()));
158+
LocalTool.Object.WithValidation(sp.GetService<IValidator>()!));
159159

160160
LocalTool = new OnePasswordToolMock();
161161
RemoteTool = new OnePasswordRemoteTool(
162-
new OnePasswordApiTestClientFactory(_apiTestFixture.CreateClient()));
162+
new OnePasswordApiTestClientFactory(_apiTestFixture.CreateClient(), new NewtonsoftAppyJsonSerializer()));
163163

164164
Organization = "appy";
165165
Environment = "DEV";

src/Directory.Build.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444

4545
<PropertyGroup Label="Package Versions">
4646
<MicrosoftWin32RegistryPackageVersion>5.0.0</MicrosoftWin32RegistryPackageVersion>
47-
<FlurlPackageVersion>3.0.0</FlurlPackageVersion>
4847
<NewtonsoftJsonPackageVersion>12.0.3</NewtonsoftJsonPackageVersion>
4948
<MedallionShellPackageVersion>1.6.1</MedallionShellPackageVersion>
5049
<McMasterExtensionsCommandLineUtilsPackageVersion>3.1.0-rc.371</McMasterExtensionsCommandLineUtilsPackageVersion>

0 commit comments

Comments
 (0)