A modern .NET library for accessing German public holidays through the Feiertage API.
- Simple & Intuitive API - Easy-to-use methods for querying German public holidays
- Async/Await Support - Fully asynchronous with
TaskandIAsyncEnumerable - Streaming Support - Memory-efficient streaming for large datasets
- Resilient HTTP Client - Built-in retry policies and circuit breakers
- Structured Logging - Integrated with
Microsoft.Extensions.Logging - Rich Exception Handling - Detailed error information with custom exception types
- Dependency Injection - First-class support for .NET DI
- Disposable Pattern - Supports both IDisposable and IAsyncDisposable for standalone usage
- Strongly-Typed States - Type-safe
GermanStateenum with IntelliSense support - Native AOT & Trim Friendly - Both packages are marked
<IsAotCompatible>true</IsAotCompatible>and ship a source-generatedJsonSerializerContext— no reflection at the JSON entry point, no AOT/trim analyzer warnings when consumed from aPublishAot=trueapp
dotnet add package FeiertageApiPerfect for console apps, scripts, or simple applications:
using FeiertageApi.Clients;
using FeiertageApi.Models;
// Using statement ensures proper disposal
using var client = new FeiertageApiClient();
var holidays = await client.GetPublicHolidays(2024, GermanState.Bavaria);
foreach (var holiday in holidays.Holidays)
{
Console.WriteLine($"{holiday.Date:yyyy-MM-dd}: {holiday.Name}");
}
// Or with async disposal
await using var client2 = new FeiertageApiClient();
var response = await client2.GetPublicHolidays(2025, GermanState.Berlin);Recommended for ASP.NET Core and larger applications. Requires the separate FeiertageApi.Extensions.AspNetCore package:
dotnet add package FeiertageApi.Extensions.AspNetCoreusing FeiertageApi.Extensions.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
// Add FeiertageApi client with resilience handling
builder.Services.AddFeiertageApi();
var app = builder.Build();using FeiertageApi.Clients;
using FeiertageApi.Models;
public class HolidayService
{
private readonly IFeiertageApiClient _client;
public HolidayService(IFeiertageApiClient client)
{
_client = client;
}
public async Task<HolidayResponse> GetBavarianHolidays()
{
// Get holidays for Bavaria in 2024 - strongly-typed!
return await _client.GetPublicHolidays(2024, GermanState.Bavaria);
}
}using FeiertageApi.Models;
// Single state - type-safe with IntelliSense
var holidays = await client.GetPublicHolidays(2024, GermanState.Bavaria);
// Multiple states
var holidays2 = await client.GetPublicHolidays(
year: 2024,
states: new[] { GermanState.Bavaria, GermanState.Berlin }
);
// Multiple years and states
var holidays3 = await client.GetPublicHolidays(
years: new[] { 2024, 2025 },
states: new[] { GermanState.Bavaria, GermanState.Berlin, GermanState.Hamburg }
);// Get all holidays for 2024
var response = await client.GetPublicHolidays(2024);
foreach (var holiday in response.Holidays)
{
Console.WriteLine($"{holiday.Date:yyyy-MM-dd}: {holiday.Name}");
}// Get only Catholic holidays for Bavaria in 2024
var response = await client.GetPublicHolidays(
year: 2024,
state: GermanState.Bavaria,
catholic: true
);// Get holidays for 2024, 2025, and 2026
var response = await client.GetPublicHolidays(
years: new[] { 2024, 2025, 2026 },
states: new[] { GermanState.Bavaria }
);// Stream holidays one at a time - great for large datasets
await foreach (var holiday in client.StreamPublicHolidays(2024, GermanState.Bavaria))
{
Console.WriteLine($"{holiday.Date:yyyy-MM-dd}: {holiday.Name}");
// Process each holiday without loading all into memory
await ProcessHolidayAsync(holiday);
}
// Stream multiple states
await foreach (var holiday in client.StreamPublicHolidays(
new[] { 2024, 2025 },
new[] { GermanState.Bavaria, GermanState.Berlin }))
{
Console.WriteLine($"{holiday.Date}: {holiday.Name}");
}var request = new HolidayRequest(
Years: new[] { 2024 },
States: new[] { GermanState.Bavaria, GermanState.BadenWuerttemberg },
AllStates: false,
Catholic: true,
Augsburg: null
);
var response = await client.GetPublicHolidays(request);The library provides detailed exception types for different error scenarios:
using FeiertageApi.Exceptions;
try
{
var response = await client.GetPublicHolidays(2024, GermanState.Bavaria);
}
catch (FeiertageApiHttpException ex)
{
// HTTP communication error (network, timeout, etc.)
Console.WriteLine($"HTTP Error: {ex.StatusCode}");
Console.WriteLine($"Request URI: {ex.RequestUri}");
}
catch (FeiertageApiResponseException ex)
{
// API returned an error response
Console.WriteLine($"API Error: {ex.ErrorDescription}");
Console.WriteLine($"API Status: {ex.ApiStatus}");
}
catch (FeiertageApiException ex)
{
// Base exception for all API errors
Console.WriteLine($"Error: {ex.Message}");
}The library integrates with Microsoft.Extensions.Logging:
// Configure logging in your application
builder.Services.AddLogging(logging =>
{
logging.AddConsole();
logging.SetMinimumLevel(LogLevel.Debug);
});Both FeiertageApi and FeiertageApi.Extensions.AspNetCore are built with <IsAotCompatible>true</IsAotCompatible> and pass the AOT / trim analyzer with zero warnings on net8.0, net9.0, and net10.0. Consumers can reference them from a PublishAot=true app without losing holiday parsing or seeing IL2026 / IL3050 warnings.
Meaning:
- JSON deserialization goes through the source-generated
FeiertageJsonContext(JsonSerializer.Deserialize(string, JsonTypeInfo<HolidayResponse>)) — no runtime reflection to discover converters or build parser metadata. - The custom
HolidayResponseJsonConverterusesUtf8JsonReaderdirectly; the API's dynamic state-code property names ("by","be", …) are mapped to the strongly-typedGermanStateenum without reflection. GermanStateExtensions.ToStateCodeis a hardcodedswitch— no enum[Description]reflection.
Publishing an AOT-trimmed app that uses this library:
dotnet publish -c Release -r win-x64 -p:PublishAot=true- .NET 8.0, 9.0, 10.0 or later
- Internet connection to access the Feiertage API
Full API documentation is available at https://api-feiertage.de/
This library is provided as-is. The Feiertage API is provided by api-feiertage.de.
Contributions are welcome! Please feel free to submit issues or pull requests.
For issues with this library, please open an issue on GitHub.
For questions about the Feiertage API itself, visit https://api-feiertage.de/.