Skip to content

Commit 294f085

Browse files
committed
Refactor wrappers to support CancellationToken in asynchronous methods
1 parent a604308 commit 294f085

File tree

11 files changed

+254
-241
lines changed

11 files changed

+254
-241
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515

1616
- `FacturapiException.Status` now surfaces the HTTP status code when available.
1717
- Introduced `IFacturapiClient` so consumers can mock the client surface in tests.
18+
- Optional `CancellationToken` parameters on client methods to allow request cancellation from callers.
1819

1920
### Changed
2021

Wrappers/BaseWrapper.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Net.Http;
55
using System.Text;
66
using System.Threading.Tasks;
7+
using System.Threading;
78

89
namespace Facturapi.Wrappers
910
{
@@ -69,8 +70,10 @@ protected FacturapiException CreateException(string resultString, HttpResponseMe
6970
return new FacturapiException(message, status);
7071
}
7172

72-
protected async Task ThrowIfErrorAsync(HttpResponseMessage response)
73+
protected async Task ThrowIfErrorAsync(HttpResponseMessage response, CancellationToken cancellationToken = default)
7374
{
75+
cancellationToken.ThrowIfCancellationRequested();
76+
7477
if (response.IsSuccessStatusCode)
7578
{
7679
return;

Wrappers/CatalogWrapper.cs

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Net.Http;
44
using System.Threading.Tasks;
5+
using System.Threading;
56

67
namespace Facturapi.Wrappers
78
{
@@ -11,72 +12,72 @@ internal CatalogWrapper(string apiKey, string apiVersion, HttpClient httpClient)
1112
{
1213
}
1314

14-
public async Task<SearchResult<CatalogItem>> SearchProducts(Dictionary<string, object> query = null)
15+
public async Task<SearchResult<CatalogItem>> SearchProducts(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
1516
{
16-
return await this.SearchCatalogAsync(Router.SearchProductKeys(query));
17+
return await this.SearchCatalogAsync(Router.SearchProductKeys(query), cancellationToken);
1718
}
1819

19-
public async Task<SearchResult<CatalogItem>> SearchUnits(Dictionary<string, object> query = null)
20+
public async Task<SearchResult<CatalogItem>> SearchUnits(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
2021
{
21-
return await this.SearchCatalogAsync(Router.SearchUnitKeys(query));
22+
return await this.SearchCatalogAsync(Router.SearchUnitKeys(query), cancellationToken);
2223
}
2324

2425
// Carta Porte catalogs
25-
public async Task<SearchResult<CatalogItem>> SearchAirTransportCodes(Dictionary<string, object> query = null)
26+
public async Task<SearchResult<CatalogItem>> SearchAirTransportCodes(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
2627
{
27-
return await this.SearchCatalogAsync(Router.SearchCartaporteAirTransportCodes(query));
28+
return await this.SearchCatalogAsync(Router.SearchCartaporteAirTransportCodes(query), cancellationToken);
2829
}
2930

30-
public async Task<SearchResult<CatalogItem>> SearchTransportConfigs(Dictionary<string, object> query = null)
31+
public async Task<SearchResult<CatalogItem>> SearchTransportConfigs(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
3132
{
32-
return await this.SearchCatalogAsync(Router.SearchCartaporteTransportConfigs(query));
33+
return await this.SearchCatalogAsync(Router.SearchCartaporteTransportConfigs(query), cancellationToken);
3334
}
3435

35-
public async Task<SearchResult<CatalogItem>> SearchRightsOfPassage(Dictionary<string, object> query = null)
36+
public async Task<SearchResult<CatalogItem>> SearchRightsOfPassage(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
3637
{
37-
return await this.SearchCatalogAsync(Router.SearchCartaporteRightsOfPassage(query));
38+
return await this.SearchCatalogAsync(Router.SearchCartaporteRightsOfPassage(query), cancellationToken);
3839
}
3940

40-
public async Task<SearchResult<CatalogItem>> SearchCustomsDocuments(Dictionary<string, object> query = null)
41+
public async Task<SearchResult<CatalogItem>> SearchCustomsDocuments(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
4142
{
42-
return await this.SearchCatalogAsync(Router.SearchCartaporteCustomsDocuments(query));
43+
return await this.SearchCatalogAsync(Router.SearchCartaporteCustomsDocuments(query), cancellationToken);
4344
}
4445

45-
public async Task<SearchResult<CatalogItem>> SearchPackagingTypes(Dictionary<string, object> query = null)
46+
public async Task<SearchResult<CatalogItem>> SearchPackagingTypes(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
4647
{
47-
return await this.SearchCatalogAsync(Router.SearchCartaportePackagingTypes(query));
48+
return await this.SearchCatalogAsync(Router.SearchCartaportePackagingTypes(query), cancellationToken);
4849
}
4950

50-
public async Task<SearchResult<CatalogItem>> SearchTrailerTypes(Dictionary<string, object> query = null)
51+
public async Task<SearchResult<CatalogItem>> SearchTrailerTypes(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
5152
{
52-
return await this.SearchCatalogAsync(Router.SearchCartaporteTrailerTypes(query));
53+
return await this.SearchCatalogAsync(Router.SearchCartaporteTrailerTypes(query), cancellationToken);
5354
}
5455

55-
public async Task<SearchResult<CatalogItem>> SearchHazardousMaterials(Dictionary<string, object> query = null)
56+
public async Task<SearchResult<CatalogItem>> SearchHazardousMaterials(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
5657
{
57-
return await this.SearchCatalogAsync(Router.SearchCartaporteHazardousMaterials(query));
58+
return await this.SearchCatalogAsync(Router.SearchCartaporteHazardousMaterials(query), cancellationToken);
5859
}
5960

60-
public async Task<SearchResult<CatalogItem>> SearchNavalAuthorizations(Dictionary<string, object> query = null)
61+
public async Task<SearchResult<CatalogItem>> SearchNavalAuthorizations(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
6162
{
62-
return await this.SearchCatalogAsync(Router.SearchCartaporteNavalAuthorizations(query));
63+
return await this.SearchCatalogAsync(Router.SearchCartaporteNavalAuthorizations(query), cancellationToken);
6364
}
6465

65-
public async Task<SearchResult<CatalogItem>> SearchPortStations(Dictionary<string, object> query = null)
66+
public async Task<SearchResult<CatalogItem>> SearchPortStations(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
6667
{
67-
return await this.SearchCatalogAsync(Router.SearchCartaportePortStations(query));
68+
return await this.SearchCatalogAsync(Router.SearchCartaportePortStations(query), cancellationToken);
6869
}
6970

70-
public async Task<SearchResult<CatalogItem>> SearchMarineContainers(Dictionary<string, object> query = null)
71+
public async Task<SearchResult<CatalogItem>> SearchMarineContainers(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
7172
{
72-
return await this.SearchCatalogAsync(Router.SearchCartaporteMarineContainers(query));
73+
return await this.SearchCatalogAsync(Router.SearchCartaporteMarineContainers(query), cancellationToken);
7374
}
7475

75-
private async Task<SearchResult<CatalogItem>> SearchCatalogAsync(string url)
76+
private async Task<SearchResult<CatalogItem>> SearchCatalogAsync(string url, CancellationToken cancellationToken)
7677
{
77-
using (var response = await client.GetAsync(url))
78+
using (var response = await client.GetAsync(url, cancellationToken))
7879
{
79-
await this.ThrowIfErrorAsync(response);
80+
await this.ThrowIfErrorAsync(response, cancellationToken);
8081
var resultString = await response.Content.ReadAsStringAsync();
8182
var searchResult = JsonConvert.DeserializeObject<SearchResult<CatalogItem>>(resultString, this.jsonSettings);
8283
return searchResult;

Wrappers/CustomerWrapper.cs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Net.Http;
44
using System.Text;
55
using System.Threading.Tasks;
6+
using System.Threading;
67

78
namespace Facturapi.Wrappers
89
{
@@ -12,81 +13,81 @@ internal CustomerWrapper(string apiKey, string apiVersion, HttpClient httpClient
1213
{
1314
}
1415

15-
public async Task<SearchResult<Customer>> ListAsync(Dictionary<string, object> query = null)
16+
public async Task<SearchResult<Customer>> ListAsync(Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
1617
{
17-
using (var response = await client.GetAsync(Router.ListCustomers(query)))
18+
using (var response = await client.GetAsync(Router.ListCustomers(query), cancellationToken))
1819
{
19-
await this.ThrowIfErrorAsync(response);
20+
await this.ThrowIfErrorAsync(response, cancellationToken);
2021
var resultString = await response.Content.ReadAsStringAsync();
2122

2223
var searchResult = JsonConvert.DeserializeObject<SearchResult<Customer>>(resultString, this.jsonSettings);
2324
return searchResult;
2425
}
2526
}
2627

27-
public async Task<Customer> CreateAsync(Dictionary<string, object> data, Dictionary<string, object> queryParams = null)
28+
public async Task<Customer> CreateAsync(Dictionary<string, object> data, Dictionary<string, object> queryParams = null, CancellationToken cancellationToken = default)
2829
{
2930
using (var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json"))
30-
using (var response = await client.PostAsync(Router.CreateCustomer(queryParams), content))
31+
using (var response = await client.PostAsync(Router.CreateCustomer(queryParams), content, cancellationToken))
3132
{
32-
await this.ThrowIfErrorAsync(response);
33+
await this.ThrowIfErrorAsync(response, cancellationToken);
3334
var resultString = await response.Content.ReadAsStringAsync();
3435
var customer = JsonConvert.DeserializeObject<Customer>(resultString, this.jsonSettings);
3536
return customer;
3637
}
3738
}
3839

39-
public async Task<Customer> RetrieveAsync(string id)
40+
public async Task<Customer> RetrieveAsync(string id, CancellationToken cancellationToken = default)
4041
{
41-
using (var response = await client.GetAsync(Router.RetrieveCustomer(id)))
42+
using (var response = await client.GetAsync(Router.RetrieveCustomer(id), cancellationToken))
4243
{
43-
await this.ThrowIfErrorAsync(response);
44+
await this.ThrowIfErrorAsync(response, cancellationToken);
4445
var resultString = await response.Content.ReadAsStringAsync();
4546
var customer = JsonConvert.DeserializeObject<Customer>(resultString, this.jsonSettings);
4647
return customer;
4748
}
4849
}
4950

50-
public async Task<Customer> DeleteAsync(string id)
51+
public async Task<Customer> DeleteAsync(string id, CancellationToken cancellationToken = default)
5152
{
52-
using (var response = await client.DeleteAsync(Router.DeleteCustomer(id)))
53+
using (var response = await client.DeleteAsync(Router.DeleteCustomer(id), cancellationToken))
5354
{
54-
await this.ThrowIfErrorAsync(response);
55+
await this.ThrowIfErrorAsync(response, cancellationToken);
5556
var resultString = await response.Content.ReadAsStringAsync();
5657
var customer = JsonConvert.DeserializeObject<Customer>(resultString, this.jsonSettings);
5758
return customer;
5859
}
5960
}
6061

61-
public async Task<Customer> UpdateAsync(string id, Dictionary<string, object> data, Dictionary<string, object> queryParams = null)
62+
public async Task<Customer> UpdateAsync(string id, Dictionary<string, object> data, Dictionary<string, object> queryParams = null, CancellationToken cancellationToken = default)
6263
{
6364
using (var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json"))
64-
using (var response = await client.PutAsync(Router.UpdateCustomer(id, queryParams), content))
65+
using (var response = await client.PutAsync(Router.UpdateCustomer(id, queryParams), content, cancellationToken))
6566
{
66-
await this.ThrowIfErrorAsync(response);
67+
await this.ThrowIfErrorAsync(response, cancellationToken);
6768
var resultString = await response.Content.ReadAsStringAsync();
6869
var customer = JsonConvert.DeserializeObject<Customer>(resultString, this.jsonSettings);
6970
return customer;
7071
}
7172
}
7273

73-
public async Task<TaxInfoValidation> ValidateTaxInfoAsync(string id)
74+
public async Task<TaxInfoValidation> ValidateTaxInfoAsync(string id, CancellationToken cancellationToken = default)
7475
{
75-
using (var response = await client.GetAsync(Router.ValidateCustomerTaxInfo(id)))
76+
using (var response = await client.GetAsync(Router.ValidateCustomerTaxInfo(id), cancellationToken))
7677
{
77-
await this.ThrowIfErrorAsync(response);
78+
await this.ThrowIfErrorAsync(response, cancellationToken);
7879
var resultString = await response.Content.ReadAsStringAsync();
7980
var validation = JsonConvert.DeserializeObject<TaxInfoValidation>(resultString, this.jsonSettings);
8081
return validation;
8182
}
8283
}
8384

84-
public async Task SendEditLinkByEmailAsync(string id, Dictionary<string, object> data)
85+
public async Task SendEditLinkByEmailAsync(string id, Dictionary<string, object> data, CancellationToken cancellationToken = default)
8586
{
8687
using (var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json"))
87-
using (var response = await client.PostAsync(Router.SendEditLinkByEmail(id), content))
88+
using (var response = await client.PostAsync(Router.SendEditLinkByEmail(id), content, cancellationToken))
8889
{
89-
await this.ThrowIfErrorAsync(response);
90+
await this.ThrowIfErrorAsync(response, cancellationToken);
9091
}
9192
}
9293
}

0 commit comments

Comments
 (0)