mirror of
https://github.com/Sarsoo/Spotify.NET.git
synced 2024-12-23 14:46:26 +00:00
Added paging methods, closes #538
This commit is contained in:
parent
8dd31420ea
commit
237925d51e
96
SpotifyAPI.Web.Tests/Clients/SpotifyClientTest.cs
Normal file
96
SpotifyAPI.Web.Tests/Clients/SpotifyClientTest.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using SpotifyAPI.Web.Http;
|
||||
|
||||
namespace SpotifyAPI.Web.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SpotifyClientTest
|
||||
{
|
||||
[Test]
|
||||
public async Task NextPageForIPaginatable()
|
||||
{
|
||||
var api = new Mock<IAPIConnector>();
|
||||
var config = SpotifyClientConfig.CreateDefault("FakeToken").WithAPIConnector(api.Object);
|
||||
var spotify = new SpotifyClient(config);
|
||||
|
||||
var response = new SearchResponse
|
||||
{
|
||||
Albums = new Paging<SimpleAlbum, SearchResponse>
|
||||
{
|
||||
Next = "https://next-url",
|
||||
}
|
||||
};
|
||||
|
||||
await spotify.NextPage(response.Albums);
|
||||
api.Verify(a => a.Get<SearchResponse>(new System.Uri("https://next-url")), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task NextPageForCursorPaging()
|
||||
{
|
||||
var api = new Mock<IAPIConnector>();
|
||||
var config = SpotifyClientConfig.CreateDefault("FakeToken").WithAPIConnector(api.Object);
|
||||
var spotify = new SpotifyClient(config);
|
||||
|
||||
var response = new CursorPaging<PlayHistoryItem>
|
||||
{
|
||||
Next = "https://next-url"
|
||||
};
|
||||
|
||||
await spotify.NextPage(response);
|
||||
api.Verify(a => a.Get<CursorPaging<PlayHistoryItem>>(new System.Uri("https://next-url")), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task NextPageForPaging()
|
||||
{
|
||||
var api = new Mock<IAPIConnector>();
|
||||
var config = SpotifyClientConfig.CreateDefault("FakeToken").WithAPIConnector(api.Object);
|
||||
var spotify = new SpotifyClient(config);
|
||||
|
||||
var response = new Paging<PlayHistoryItem>
|
||||
{
|
||||
Next = "https://next-url"
|
||||
};
|
||||
|
||||
await spotify.NextPage(response);
|
||||
api.Verify(a => a.Get<Paging<PlayHistoryItem>>(new System.Uri("https://next-url")), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PreviousPageForPaging()
|
||||
{
|
||||
var api = new Mock<IAPIConnector>();
|
||||
var config = SpotifyClientConfig.CreateDefault("FakeToken").WithAPIConnector(api.Object);
|
||||
var spotify = new SpotifyClient(config);
|
||||
|
||||
var response = new Paging<PlayHistoryItem>
|
||||
{
|
||||
Previous = "https://previous-url"
|
||||
};
|
||||
|
||||
await spotify.PreviousPage(response);
|
||||
api.Verify(a => a.Get<Paging<PlayHistoryItem>>(new System.Uri("https://previous-url")), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PreviousPageForCustomPaging()
|
||||
{
|
||||
var api = new Mock<IAPIConnector>();
|
||||
var config = SpotifyClientConfig.CreateDefault("FakeToken").WithAPIConnector(api.Object);
|
||||
var spotify = new SpotifyClient(config);
|
||||
|
||||
var response = new Paging<PlayHistoryItem, SearchResponse>
|
||||
{
|
||||
Previous = "https://previous-url"
|
||||
};
|
||||
|
||||
await spotify.PreviousPage(response);
|
||||
api.Verify(a => a.Get<SearchResponse>(new System.Uri("https://previous-url")), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
@ -167,5 +167,15 @@ namespace SpotifyAPI.Web
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
public Task<Paging<T>> NextPage<T>(Paging<T> paging);
|
||||
|
||||
public Task<CursorPaging<T>> NextPage<T>(CursorPaging<T> cursorPaging);
|
||||
|
||||
public Task<TNext> NextPage<T, TNext>(IPaginatable<T, TNext> paginatable);
|
||||
|
||||
public Task<Paging<T>> PreviousPage<T>(Paging<T> paging);
|
||||
|
||||
public Task<TNext> PreviousPage<T, TNext>(Paging<T, TNext> paging);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SpotifyAPI.Web.Http;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace SpotifyAPI.Web
|
||||
{
|
||||
@ -29,14 +29,7 @@ namespace SpotifyAPI.Web
|
||||
#pragma warning restore CA2208
|
||||
}
|
||||
|
||||
_apiConnector = new APIConnector(
|
||||
config.BaseAddress,
|
||||
config.Authenticator,
|
||||
config.JSONSerializer,
|
||||
config.HTTPClient,
|
||||
config.RetryHandler,
|
||||
config.HTTPLogger
|
||||
);
|
||||
_apiConnector = config.BuildAPIConnector();
|
||||
_apiConnector.ResponseReceived += (sender, response) =>
|
||||
{
|
||||
LastResponse = response;
|
||||
@ -124,6 +117,79 @@ namespace SpotifyAPI.Web
|
||||
return (paginator ?? DefaultPaginator).PaginateAll(firstPage, mapper, _apiConnector);
|
||||
}
|
||||
|
||||
private Task<T> FetchPage<T>(string? nextUrl)
|
||||
{
|
||||
if (nextUrl == null)
|
||||
{
|
||||
throw new APIPagingException("The paging object has no next page");
|
||||
}
|
||||
|
||||
return _apiConnector.Get<T>(new Uri(nextUrl, UriKind.Absolute));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the next page of the paging object
|
||||
/// </summary>
|
||||
/// <param name="paging">A paging object which has a next page</param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public Task<Paging<T>> NextPage<T>(Paging<T> paging)
|
||||
{
|
||||
Ensure.ArgumentNotNull(paging, nameof(paging));
|
||||
return FetchPage<Paging<T>>(paging.Next);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the next page of the cursor paging object
|
||||
/// </summary>
|
||||
/// <param name="cursorPaging">A cursor paging object which has a next page</param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public Task<CursorPaging<T>> NextPage<T>(CursorPaging<T> cursorPaging)
|
||||
{
|
||||
Ensure.ArgumentNotNull(cursorPaging, nameof(cursorPaging));
|
||||
return FetchPage<CursorPaging<T>>(cursorPaging.Next);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the next page of the complex IPaginatable object.
|
||||
/// </summary>
|
||||
/// <param name="paginatable">A complex IPaginatable object with a next page</param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TNext">The type of the next page</typeparam>
|
||||
/// <returns></returns>
|
||||
public Task<TNext> NextPage<T, TNext>(IPaginatable<T, TNext> paginatable)
|
||||
{
|
||||
Ensure.ArgumentNotNull(paginatable, nameof(paginatable));
|
||||
return FetchPage<TNext>(paginatable.Next);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the previous page of the paging object.
|
||||
/// </summary>
|
||||
/// <param name="paging">A paging object with a previous page</param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public Task<Paging<T>> PreviousPage<T>(Paging<T> paging)
|
||||
{
|
||||
Ensure.ArgumentNotNull(paging, nameof(paging));
|
||||
return FetchPage<Paging<T>>(paging.Previous);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the previous page of the complex paging object.
|
||||
/// </summary>
|
||||
/// <param name="paging">A complex paging object with a previous page</param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TNext">The type of the next page</typeparam>
|
||||
/// <returns></returns>
|
||||
public Task<TNext> PreviousPage<T, TNext>(Paging<T, TNext> paging)
|
||||
{
|
||||
Ensure.ArgumentNotNull(paging, nameof(paging));
|
||||
return FetchPage<TNext>(paging.Previous);
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_1
|
||||
|
||||
/// <summary>
|
||||
|
@ -13,6 +13,7 @@ namespace SpotifyAPI.Web
|
||||
public IHTTPLogger? HTTPLogger { get; private set; }
|
||||
public IRetryHandler? RetryHandler { get; private set; }
|
||||
public IPaginator DefaultPaginator { get; private set; }
|
||||
public IAPIConnector? APIConnector { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This config spefies the internal parts of the SpotifyClient.
|
||||
@ -24,6 +25,7 @@ namespace SpotifyAPI.Web
|
||||
/// <param name="retryHandler"></param>
|
||||
/// <param name="httpLogger"></param>
|
||||
/// <param name="defaultPaginator"></param>
|
||||
/// <param name="apiConnector"></param>
|
||||
public SpotifyClientConfig(
|
||||
Uri baseAddress,
|
||||
IAuthenticator? authenticator,
|
||||
@ -31,7 +33,8 @@ namespace SpotifyAPI.Web
|
||||
IHTTPClient httpClient,
|
||||
IRetryHandler? retryHandler,
|
||||
IHTTPLogger? httpLogger,
|
||||
IPaginator defaultPaginator
|
||||
IPaginator defaultPaginator,
|
||||
IAPIConnector? apiConnector = null
|
||||
)
|
||||
{
|
||||
BaseAddress = baseAddress;
|
||||
@ -41,6 +44,7 @@ namespace SpotifyAPI.Web
|
||||
RetryHandler = retryHandler;
|
||||
HTTPLogger = httpLogger;
|
||||
DefaultPaginator = defaultPaginator;
|
||||
APIConnector = apiConnector;
|
||||
}
|
||||
|
||||
public SpotifyClientConfig WithToken(string token, string tokenType = "Bearer")
|
||||
@ -145,6 +149,34 @@ namespace SpotifyAPI.Web
|
||||
);
|
||||
}
|
||||
|
||||
public SpotifyClientConfig WithAPIConnector(IAPIConnector apiConnector)
|
||||
{
|
||||
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
|
||||
|
||||
return new SpotifyClientConfig(
|
||||
BaseAddress,
|
||||
Authenticator,
|
||||
JSONSerializer,
|
||||
HTTPClient,
|
||||
RetryHandler,
|
||||
HTTPLogger,
|
||||
DefaultPaginator,
|
||||
apiConnector
|
||||
);
|
||||
}
|
||||
|
||||
public IAPIConnector BuildAPIConnector()
|
||||
{
|
||||
return APIConnector ?? new APIConnector(
|
||||
BaseAddress,
|
||||
Authenticator,
|
||||
JSONSerializer,
|
||||
HTTPClient,
|
||||
RetryHandler,
|
||||
HTTPLogger
|
||||
);
|
||||
}
|
||||
|
||||
public static SpotifyClientConfig CreateDefault(string token, string tokenType = "Bearer")
|
||||
{
|
||||
return CreateDefault().WithAuthenticator(new TokenAuthenticator(token, tokenType));
|
||||
|
31
SpotifyAPI.Web/Exceptions/APIPagingException.cs
Normal file
31
SpotifyAPI.Web/Exceptions/APIPagingException.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using SpotifyAPI.Web.Http;
|
||||
|
||||
namespace SpotifyAPI.Web
|
||||
{
|
||||
[Serializable]
|
||||
public class APIPagingException : APIException
|
||||
{
|
||||
public TimeSpan RetryAfter { get; }
|
||||
|
||||
public APIPagingException(IResponse response) : base(response)
|
||||
{
|
||||
Ensure.ArgumentNotNull(response, nameof(response));
|
||||
|
||||
if (response.Headers.TryGetValue("Retry-After", out string? retryAfter))
|
||||
{
|
||||
RetryAfter = TimeSpan.FromSeconds(int.Parse(retryAfter, CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
public APIPagingException() { }
|
||||
|
||||
public APIPagingException(string message) : base(message) { }
|
||||
|
||||
public APIPagingException(string message, Exception innerException) : base(message, innerException) { }
|
||||
|
||||
protected APIPagingException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user