Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7300578
feat: adding initial implementation for pagination
haseeb-mhr May 27, 2025
f023b0f
Adding page to item converter in ApiCall
haseeb-mhr May 30, 2025
9d467f8
Update ApiCall.cs
hamzamahmood May 30, 2025
5a6912d
Merge branch 'feat/pagination-implementation' of https://github.com/a…
hamzamahmood May 30, 2025
f53304c
Update ApiCall.cs
hamzamahmood May 30, 2025
0970d4d
Update ApiCall.cs
hamzamahmood May 30, 2025
731d644
add unit test for AsyncPaginator for query
hamzamahmood Jun 4, 2025
b2c32c3
Unit tests added
hamzamahmood Jun 10, 2025
1a84fdb
- add unit tests for HeaderParam and TemplateParam updateByReference
hamzamahmood Jun 11, 2025
a6ddd41
refactor code
hamzamahmood Jun 12, 2025
e975d6b
reactor code to fix code climate errors
hamzamahmood Jun 12, 2025
524993c
Update JsonPointerAccessor.cs
hamzamahmood Jun 12, 2025
09feb61
Update JsonPointerAccessor.cs
hamzamahmood Jun 12, 2025
7929eb6
adds body support in pagination updateByReference
hamzamahmood Jun 12, 2025
2ad2da3
Update RequestBuilder.cs
hamzamahmood Jun 12, 2025
6557fdd
Add body UpdateByReference Tests and refactor code
hamzamahmood Jun 12, 2025
43f4810
Update RequestBuilderExtensions.cs
hamzamahmood Jun 12, 2025
e0ae094
incorporate refactoring by @haseeb-mhr
hamzamahmood Jun 12, 2025
5940db5
add support and unit test for narrow down pagination strategy
hamzamahmood Jun 13, 2025
5f7046c
refactor code to remove duplicate logic
hamzamahmood Jun 13, 2025
e5742f2
Update AsyncPaginator.cs
hamzamahmood Jun 13, 2025
71e5010
revert pattern matching to switch case for backward compatibility
hamzamahmood Jun 16, 2025
77b2372
fix: address PR review comments
hamzamahmood Jun 17, 2025
1a5dd9d
fix(request-builder): ensure AuthGroup is correctly copied in copy co…
hamzamahmood Jun 17, 2025
aa340c9
fix: validate empty strategies in constructors and add PolySharp for …
hamzamahmood Jun 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions APIMatic.Core.Test/Api/ApiCallTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ namespace APIMatic.Core.Test.Api
{
public class ApiCallTest : TestBase
{
private static readonly MockServer _server = MockServer.Server1;
private static readonly CompatibilityFactory _compatibilityFactory = new();
private static readonly Dictionary<string, ErrorCase<HttpRequest, HttpResponse, HttpContext, ApiException>> _globalErrors = new()
private static readonly MockServer Server = MockServer.Server1;
private static readonly CompatibilityFactory CompatibilityFactory = new();
private static readonly Dictionary<string, ErrorCase<HttpRequest, HttpResponse, HttpContext, ApiException>> GlobalErrors = new()
{
{ "400", CreateErrorCase("400 Global Child 1", (reason, context) => new Child1Exception(reason, context)) },
{ "402", CreateErrorCase("402 Global Child 2", (reason, context) => new Child2Exception(reason, context)) },
Expand All @@ -25,34 +25,34 @@ public class ApiCallTest : TestBase
protected static ErrorCase<HttpRequest, HttpResponse, HttpContext, ApiException> CreateErrorCase(string reason, Func<string, HttpContext, ApiException> error, bool isErrorTemplate = false)
=> new(reason, error, isErrorTemplate);

protected ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, ApiResponse<T>, T> CreateApiCall<T>()
protected static ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, ApiResponse<T>, T> CreateApiCall<T>()
=> new ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, ApiResponse<T>, T>(
LazyGlobalConfiguration.Value,
_compatibilityFactory,
globalErrors: _globalErrors,
CompatibilityFactory,
globalErrors: GlobalErrors,
returnTypeCreator: (response, result) => new ApiResponse<T>(response.StatusCode, response.Headers, result)
).Server(_server);
).Server(Server);

protected ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, ApiResponse<T>, T> CreateApiCallWithoutReturnTypeCreator<T>()
protected static ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, ApiResponse<T>, T> CreateApiCallWithoutReturnTypeCreator<T>()
=> new ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, ApiResponse<T>, T>(
LazyGlobalConfiguration.Value,
_compatibilityFactory
).Server(_server);
CompatibilityFactory
).Server(Server);

protected ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, T, T> CreateSimpleApiCall<T>()
protected static ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, T, T> CreateSimpleApiCall<T>()
=> new ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, T, T>(
LazyGlobalConfiguration.Value,
_compatibilityFactory,
globalErrors: _globalErrors
).Server(_server);
CompatibilityFactory,
globalErrors: GlobalErrors
).Server(Server);

protected ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, T, T> CreateSimpleApiCallWithoutErrors<T>()
protected static ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, T, T> CreateSimpleApiCallWithoutErrors<T>()
=> new ApiCall<HttpRequest, HttpResponse, HttpContext, ApiException, T, T>(
LazyGlobalConfiguration.Value,
_compatibilityFactory
).Server(_server);

protected string GetCompleteUrl(string path)
CompatibilityFactory
).Server(Server);
protected static string GetCompleteUrl(string path)
{
return $"{LazyGlobalConfiguration.Value.ServerUrl()}{path}";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
namespace APIMatic.Core.Test.Api.HttpPost
{
[TestFixture]
internal class ApiCallPostXMLTest : ApiCallTest
internal class ApiCallPostXmlTest : ApiCallTest
{
[Test]
public void ApiCall_PostXmlLong_OKResponse()
{
//Arrange
long body = 100;
var url = "/apicall/post-xml-long/200";
const long body = 100;
const string url = "/apicall/post-xml-long/200";

var expected = new ServerResponse()
{
Expand All @@ -28,7 +28,7 @@ public void ApiCall_PostXmlLong_OKResponse()
handlerMock.When(GetCompleteUrl(url))
.With(req =>
{
Assert.AreEqual(expected.Message, req.Content.ReadAsStringAsync().Result);
Assert.AreEqual(expected.Message, req.Content?.ReadAsStringAsync().Result);
return true;
})
.Respond(HttpStatusCode.OK, content);
Expand Down Expand Up @@ -57,7 +57,7 @@ public void ApiCall_PostXmlLong_OKResponse()
public void ApiCall_PostXmlString_OKResponse()
{
//Arrange
string body = "This is a xml body.";
var body = "This is a xml body.";
var url = "/apicall/post-xml-string/200";

var expected = new ServerResponse()
Expand All @@ -70,7 +70,7 @@ public void ApiCall_PostXmlString_OKResponse()
handlerMock.When(GetCompleteUrl(url))
.With(req =>
{
Assert.AreEqual(expected.Message, req.Content.ReadAsStringAsync().Result);
Assert.AreEqual(expected.Message, req.Content?.ReadAsStringAsync().Result);
return true;
})
.Respond(HttpStatusCode.OK, content);
Expand Down
11 changes: 1 addition & 10 deletions APIMatic.Core.Test/AuthenticationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public void Multiple_Authentication_OR_Validation_Failure()
}

[Test]
public async Task Multiple_Authentication_AND_Validation_Failure()
public void Multiple_Authentication_AND_Validation_Failure()
{
var globalConfiguration = new GlobalConfiguration.Builder()
.ServerUrls(new Dictionary<Enum, string>
Expand All @@ -137,15 +137,6 @@ public async Task Multiple_Authentication_AND_Validation_Failure()

Assert.AreEqual("Following authentication credentials are required:\n" +
"-> Missing required header field: TOKEN", exp.Message);

async void AuthCode()
{
await globalConfiguration.GlobalRequestBuilder()
.Setup(HttpMethod.Get, "/auth")
.WithAndAuth(auth => auth.Add("query")
.Add("header"))
.Build();
}
}

[Test]
Expand Down
45 changes: 45 additions & 0 deletions APIMatic.Core.Test/MockTypes/Models/Pagination/Transaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using APIMatic.Core.Test.MockTypes.Convertors;
using Newtonsoft.Json;

namespace APIMatic.Core.Test.MockTypes.Models.Pagination
{
public class Transaction
{
/// <summary>
/// Initializes a new instance of the <see cref="Transaction"/> class.
/// </summary>
/// <param name="id">id.</param>
/// <param name="amount">amount.</param>
/// <param name="timestamp">timestamp.</param>
public Transaction(
string id = null,
double? amount = null,
DateTime? timestamp = null)
{
this.Id = id;
this.Amount = amount;
this.Timestamp = timestamp;
}

/// <summary>
/// Gets or sets Id.
/// </summary>
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }

/// <summary>
/// Gets or sets Amount.
/// </summary>
[JsonProperty("amount", NullValueHandling = NullValueHandling.Ignore)]
public double? Amount { get; set; }

/// <summary>
/// Gets or sets Timestamp.
/// </summary>
[JsonConverter(typeof(CustomDateTimeConverter), "r")]
[JsonProperty("timestamp", NullValueHandling = NullValueHandling.Ignore)]
public DateTime? Timestamp { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace APIMatic.Core.Test.MockTypes.Models.Pagination
{
public class TransactionsCursored
{
private string nextCursor;
private readonly Dictionary<string, bool> shouldSerialize = new Dictionary<string, bool>
{
{ "nextCursor", false },
};

/// <summary>
/// Initializes a new instance of the <see cref="TransactionsCursored"/> class.
/// </summary>
/// <param name="data">data.</param>
/// <param name="nextCursor">nextCursor.</param>
public TransactionsCursored(
List<Transaction> data = null,
string nextCursor = null)
{
this.Data = data;

if (nextCursor != null)
{
this.NextCursor = nextCursor;
}
}

/// <summary>
/// Gets or sets Data.
/// </summary>
[JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
public List<Transaction> Data { get; set; }

/// <summary>
/// Cursor for the next page of results.
/// </summary>
[JsonProperty("nextCursor")]
public string NextCursor
{
get
{
return this.nextCursor;
}

set
{
this.shouldSerialize["nextCursor"] = true;
this.nextCursor = value;
}
}

/// <summary>
/// Marks the field to not be serialized.
/// </summary>
public void UnsetNextCursor()
{
this.shouldSerialize["nextCursor"] = false;
}

/// <summary>
/// Checks if the field should be serialized or not.
/// </summary>
/// <returns>A boolean weather the field should be serialized or not.</returns>
public bool ShouldSerializeNextCursor()
{
return this.shouldSerialize["nextCursor"];
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace APIMatic.Core.Test.MockTypes.Models.Pagination
{
public class TransactionsLinked
{
/// <summary>
/// Initializes a new instance of the <see cref="TransactionsLinked"/> class.
/// </summary>
/// <param name="data">data.</param>
/// <param name="links">links.</param>
public TransactionsLinked(
List<Transaction> data = null,
Links links = null)
{
this.Data = data;
this.Links = links;
}

/// <summary>
/// Gets or sets Data.
/// </summary>
[JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
public List<Transaction> Data { get; set; }

/// <summary>
/// Gets or sets Links.
/// </summary>
[JsonProperty("links", NullValueHandling = NullValueHandling.Ignore)]
public Links Links { get; set; }
}

public class Links
{
/// <summary>
/// Initializes a new instance of the <see cref="Links"/> class.
/// </summary>
/// <param name="first">first.</param>
/// <param name="last">last.</param>
/// <param name="prev">prev.</param>
/// <param name="next">next.</param>
public Links(
string first = null,
string last = null,
string prev = null,
string next = null)
{
this.First = first;
this.Last = last;
this.Prev = prev;
this.Next = next;
}

/// <summary>
/// Gets or sets First.
/// </summary>
[JsonProperty("first", NullValueHandling = NullValueHandling.Ignore)]
public string First { get; set; }

/// <summary>
/// Gets or sets Last.
/// </summary>
[JsonProperty("last", NullValueHandling = NullValueHandling.Ignore)]
public string Last { get; set; }

/// <summary>
/// Gets or sets Prev.
/// </summary>
[JsonProperty("prev", NullValueHandling = NullValueHandling.Ignore)]
public string Prev { get; set; }

/// <summary>
/// Gets or sets Next.
/// </summary>
[JsonProperty("next", NullValueHandling = NullValueHandling.Ignore)]
public string Next { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace APIMatic.Core.Test.MockTypes.Models.Pagination
{
public class TransactionsOffset
{
/// <summary>
/// Initializes a new instance of the <see cref="TransactionsOffset"/> class.
/// </summary>
/// <param name="data">data.</param>
public TransactionsOffset(
List<Transaction> data = null)
{
this.Data = data;
}

/// <summary>
/// Gets or sets Data.
/// </summary>
[JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
public List<Transaction> Data { get; set; }
}
}
8 changes: 8 additions & 0 deletions APIMatic.Core.Test/MockTypes/Models/Pagination/User.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace APIMatic.Core.Test.MockTypes.Models.Pagination
{
internal sealed class User
{
public int Id { get; init; }
public string Name { get; init; }
}
}
13 changes: 13 additions & 0 deletions APIMatic.Core.Test/MockTypes/Models/Person.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Newtonsoft.Json;

namespace APIMatic.Core.Test.MockTypes.Models
{
public class Person
{
[JsonProperty("name")]
public string Name { get; init; }

[JsonProperty("age")]
public int Age { get; init; }
}
}
Loading