Skip to content

rootasjey/unsplasharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

52 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Unsplasharp

Unsplasharp

NuGet NuGet License

Unofficial C# wrapper around Unsplash API targeting .NET Standard 2.0.

This lib is compatible with .NET Core, .NET Framework 4.6.1+, Xamarin (iOS, Android), Universal Windows Platform.

✨ Recent Improvements

This library has been enhanced with modern .NET practices and reliability features:

  • πŸ”„ Async/Await Patterns: Improved async patterns with proper ConfigureAwait(false) usage
  • ⏹️ Cancellation Token Support: All async methods now support CancellationToken for request cancellation and timeouts
  • πŸ“Š Structured Logging: Built-in support for Microsoft.Extensions.Logging with detailed request/response logging
  • πŸ” Retry Policies: Automatic retry logic using Polly for resilient HTTP requests
  • ⚑ Performance: Migrated to System.Text.Json for 2-3x faster JSON processing and reduced memory usage
  • πŸ›‘οΈ Comprehensive Error Handling: Structured exceptions with rich context for better debugging and error recovery
  • πŸš€ Modern JSON: System.Text.Json integration with custom converters and safe property access

Currently incomplete 🚧

πŸ“– Documentation

Comprehensive documentation is available with guides for all experience levels:

Quick Navigation

Installation

NuGet: Install-Package unsplasharp.api

Usage

Basic Usage

using Unsplasharp;

var client = new UnsplasharpClient("YOUR_APPLICATION_ID");
var photosFound = await client.SearchPhotos("mountains");

Cancellation Token Support

All async methods now support CancellationToken for request cancellation and timeout handling:

using Unsplasharp;

var client = new UnsplasharpClient("YOUR_APPLICATION_ID");

// Timeout after 30 seconds
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var photo = await client.GetRandomPhoto(cts.Token);

// Manual cancellation
using var cts2 = new CancellationTokenSource();
var searchTask = client.SearchPhotos("nature", 1, 10, cts2.Token);
// Later: cts2.Cancel();

// Integration with ASP.NET Core
public async Task<IActionResult> GetPhoto(string id, CancellationToken cancellationToken)
{
    var photo = await client.GetPhoto(id, 0, 0, cancellationToken);
    return Ok(photo);
}

Supported Methods:

  • All photo methods: GetPhoto(), GetRandomPhoto(), ListPhotos(), SearchPhotos()
  • All collection methods: GetCollection(), ListCollections(), GetCollectionPhotos()
  • All user methods: GetUser()
  • All search methods: SearchPhotos(), SearchCollections()
  • Stats methods: GetTotalStats()

πŸ”„ Backward Compatibility: All existing method signatures remain unchanged. Cancellation token support is added as optional overloads, so your existing code will continue to work without any modifications.

Advanced Usage with Logging

using Unsplasharp;
using Microsoft.Extensions.Logging;

// Create a logger factory
using var loggerFactory = LoggerFactory.Create(builder =>
    builder.AddConsole().SetMinimumLevel(LogLevel.Debug));

var logger = loggerFactory.CreateLogger<UnsplasharpClient>();

// Create client with logging support
var client = new UnsplasharpClient("YOUR_APPLICATION_ID", logger: logger);

// The client will now log HTTP requests, retries, and errors
var photos = await client.SearchPhotos("nature");

Modern Usage with IHttpClientFactory (Recommended)

For ASP.NET Core and modern .NET applications, use the IHttpClientFactory integration:

using Unsplasharp.Extensions;

// In Program.cs or Startup.cs
builder.Services.AddUnsplasharp("YOUR_APPLICATION_ID");

// Or with configuration
builder.Services.AddUnsplasharp(options =>
{
    options.ApplicationId = "YOUR_APPLICATION_ID";
    options.Secret = "YOUR_SECRET"; // Optional
    options.ConfigureHttpClient = client =>
    {
        client.Timeout = TimeSpan.FromSeconds(60);
    };
});

// In your controller or service
public class PhotoService
{
    private readonly UnsplasharpClient _client;

    public PhotoService(UnsplasharpClient client)
    {
        _client = client;
    }

    public async Task<List<Photo>> GetPhotos(string query)
    {
        return await _client.SearchPhotos(query);
    }
}

Features

  • 🏭 IHttpClientFactory Support: Modern HTTP client management with proper lifecycle and DI integration
  • πŸ”„ Automatic Retries: Failed requests are automatically retried up to 3 times with exponential backoff
  • πŸ“Š Structured Logging: Detailed logging of HTTP requests, responses, and retry attempts
  • πŸ“ˆ Rate Limit Tracking: Built-in rate limit monitoring and logging
  • ⚑ Async/Await: All methods use proper async patterns with ConfigureAwait(false)
  • πŸš€ High Performance JSON: System.Text.Json for faster parsing and lower memory usage
  • πŸ”§ Dependency Injection: Seamless integration with .NET DI containers
  • πŸ”™ Backward Compatible: Existing code continues to work without changes

Comprehensive Error Handling

Unsplasharp now provides structured exception handling with rich context information for better debugging and error recovery:

try {
    // New methods that throw specific exceptions
    var photo = await client.GetRandomPhotoAsync();
    var specificPhoto = await client.GetPhotoAsync("photo-id");
} catch (UnsplasharpNotFoundException ex) {
    // Handle resource not found (404)
    Console.WriteLine($"Photo '{ex.ResourceId}' not found");
} catch (UnsplasharpRateLimitException ex) {
    // Handle rate limiting (429)
    Console.WriteLine($"Rate limit exceeded. Reset at: {ex.RateLimitReset}");
    await Task.Delay(ex.TimeUntilReset ?? TimeSpan.FromMinutes(1));
} catch (UnsplasharpAuthenticationException ex) {
    // Handle authentication errors (401)
    Console.WriteLine("Invalid application ID or access token");
} catch (UnsplasharpNetworkException ex) when (ex.IsRetryable) {
    // Handle retryable network errors
    Console.WriteLine("Temporary network error, will retry automatically");
} catch (UnsplasharpException ex) {
    // Handle any other API errors
    Console.WriteLine($"API Error: {ex.Message}");
    Console.WriteLine($"Context: {ex.Context?.ToSummary()}");
}

Key Features:

  • 🎯 Specific Exception Types: Different exceptions for different error scenarios
  • πŸ“‹ Rich Error Context: Correlation IDs, timing, rate limits, and request details
  • πŸ”„ Intelligent Retries: Automatic retry logic based on error types
  • πŸ”™ Backward Compatibility: Existing methods still return null/empty on errors
  • πŸ“Š Enhanced Logging: Structured logging with correlation IDs for debugging

For detailed information, see the Error Handling Guide.

Documentation

API documentation

Official API documentation

Instanciate a new client

It's necessary to instanciate a new client with at least an application ID to start making requests.

var client = new Client("YOUR_APPLICATION_ID");

General

Rates limits

Unsplash has API requests rates limits.

An Unsplashsharp client has two properties to help you monitor API calls:

Max API calls allowed per hour

  • MaxRateLimit

API calls remaining for the current hour

  • RateLimitRemaining
if (client.RateLimitRemaining == 0) {
  // Warning the user that he's to wait some time
  // before using the app again.
}
if (client.MaxRateLimit == 50) {
  // Application is in dev mode.
} else if (client.MaxRateLimit == 5000) {
  // Application is in prod mode.
} else { /* Unknown mode */ }

Photos

Get a single photo from an id

var photo = await client.GetPhoto("TPv9dh822VA");

// get a photo in the specified width and height in pixels
var photoWidthHeight = await client.GetPhoto(id: "TPv9dh822VA", width: 500, height: 500);

Get a random photo

var randomPhoto = await client.GetRandomPhoto();

// using collections' IDs
var randomPhotoFromCollections = await client.GetRandomPhoto(new string[] { "499830", "194162" });

// from a specific user
var randomPhotoFromUser = await client.GetRandomPhoto(count: 1, username: "matthewkane");

var randomPhotosFromQuery = await client.GetRandomPhoto(count: 3, query:"woman");

Get a list of all photos

var listPhotos = await client.ListPhotos();

var listPhotosPaged = await client.ListPhotos(page:2, perPage:15, orderBy: OrderBy.Popular);

Collections

Get a single collection from an id

var collection = await client.GetCollection("771520");

Get a list of all collections

var listCollection = await client.ListCollections();

Get a list of featured collections

var listFeaturedCollection = await client.ListFeaturedCollections();

Get a collection's photos from a collection's id

var listPhotos = await client.GetCollectionPhotos("771520");

Get related collections from a collection's id

var collectionsRelated = await client.ListRelatedCollections("771520");

Users

Get a single user from his/her username

var user = await client.GetUser("unsplash");

var userCustomProfileImage = client.GetUser("seteales", width: 100, height: 100);

Get a list of user's collections

var userCollections = await client.ListUserCollections("unsplash");

Get a list of user's photos

var userPhotos = await client.ListUserPhotos("seteales");

var userPhotosCustomParam = await client.ListUserPhotos("seteales", page: 2, perPage: 2, stats: true);

Get a list of user's liked photos

var userLikedPhotos = await client.ListUserLikedPhotos("seteales");

Get an user's statistics

var userStats = await client.GetUserStats("seteales");

Search

Search photos from a query

var photosFound = await client.SearchPhoto("mountains");

Search collections from a query

var collectionsFound = await client.SearchCollections("mountains");

Search users from a query

var usersFound = await client.SearchUsers("seteales");

Stats

Get Unsplash total stats

var totalStats = await client.GetTotalStats();

Get Unsplash monthly stats

var monthlyStats = await client.GetMonthlyStats();

Custom Requests

In adition to the previous API methods, you can build and use custom URL's to fetch photos, photos' lists, and collections' lists.

There're also methods to search for collections, photos and users using a custom URL.

Fetch a photo

var photo = await client.FetchPhoto("you_custom_url");

Fetch a list of photos

var photos = await client.FetchPhotosList("you_custom_url");

Fetch a list of collections

var collections = await client.FetchCollectionsList("you_custom_url");

Search for photos using a specific search URL

var photosFound = await client.FetchSearchPhotosList("your_custom_url");

Search for collections using a specific search URL

var collectionsFound = await client.FetchSearcCollectionsList("your_custom_url");

Search for users using a specific search URL

var usersFound = await client.FetchSearcUsersList("your_custom_url");

Tests

Tests are under UnsplashsharpTests project.

They check the Unsplash API status and that every methods in the lib works properly.

In this project, a dev API key is used which is limited to 50 requests per hour. So ensure you're not off limit.

Personal API key

If you want to get your personal API key from Unsplash:

  1. Go to Unsplash
  2. Log in or create a new account
  3. In the top bar, click on 'API/Developers'
  4. Go to 'Your applications'
  5. Click on 'New Application' to create a new one and get an API key (and a Secret).

Dependencies

  • System.Text.Json - High-performance JSON serialization (included in .NET Standard 2.0+)
  • Microsoft.Extensions.Logging.Abstractions - Structured logging support
  • Microsoft.Extensions.Http - IHttpClientFactory integration
  • Polly - Resilience and retry policies

Removed Dependencies

  • Newtonsoft.Json - Replaced with System.Text.Json for better performance

Resources

TODO