VOOZH about

URL: https://www.nuget.org/packages/YamlHttpClient/

⇱ NuGet Gallery | YamlHttpClient 2.1.1




YamlHttpClient 2.1.1

dotnet add package YamlHttpClient --version 2.1.1
 
 
NuGet\Install-Package YamlHttpClient -Version 2.1.1
 
 
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="YamlHttpClient" Version="2.1.1" />
 
 
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="YamlHttpClient" Version="2.1.1" />
 
Directory.Packages.props
<PackageReference Include="YamlHttpClient" />
 
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add YamlHttpClient --version 2.1.1
 
 
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: YamlHttpClient, 2.1.1"
 
 
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package YamlHttpClient@2.1.1
 
 
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=YamlHttpClient&version=2.1.1
 
Install as a Cake Addin
#tool nuget:?package=YamlHttpClient&version=2.1.1
 
Install as a Cake Tool
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

YamlHttpClient

YAML config-based .NET HttpClient with retry, caching, chaos engineering, and multi-step orchestration.

Download from NuGet: https://www.nuget.org/packages/YamlHttpClient/


Table of contents


Basic usage

var anyInputObject = new
{
 table = new[] { "v1", "v2" },
 date = new DateTime(2000, 1, 1),
 obj = new[] { new { test = 1 }, new { test = 2 } },
 val1 = new Dictionary<string, object>() { { "testkey", "testval" } },
 place = "urlPartDemo",
 System = new { CodeNT = "internalCode" }
};

// Load settings from a YAML file, targeting a named key
YamlHttpClientFactory httpClient = new YamlHttpClientFactory(
 new YamlHttpClientConfigBuilder().LoadFromFile("myYamlConfig.yml", "myHttpCall"));

// Build the HTTP message — placeholders are resolved from anyInputObject
var request = httpClient.BuildRequestMessage(anyInputObject);

// Optionally inspect the built content
var readContent = await request.Content.ReadAsStringAsync();

// Send
var response = await httpClient.SendAsync(request);

// Read response
var returnData = await response.Content.ReadAsStringAsync();

// Assert response matches check_response rules from config (throws if not)
await httpClient.CheckResponseAsync(response);

Or use the shorthand that combines build + send in one call:

var response = await httpClient.AutoCallAsync(anyInputObject);
await httpClient.CheckResponseAsync(response);

YAML config reference

http_client:
 myHttpCall:
 method: POST
 url: https://api.example.com/{{place}}/endpoint

 # NTLM auto-negotiation (app pool identity)
 use_default_credentials: true

 # HTTP Basic authentication
 # auth_basic: 'username:password'

 headers:
 CodeNT: '{{System.CodeNT}}'
 Accept: 'application/json'

 content:
 # JSON body with Handlebars templating
 json_content: |
 {
 "someVal": "{{val1}}",
 "flattenObj": {{{Json . ">flatten;_;_{0}" ">forcestring"}}}
 "obj": {{{Json .}}}
 }
 # Other content types (pick one):
 # string_content: 'raw text {{val}}'
 # form_content:
 # field1: value1
 # field2: '{{val}}'

 # Throws if the response body does not match expectations
 check_response:
 throw_exception_if_body_contains_any:
 - error
 throw_exception_if_body_not_contains_all:
 - success

 retry:
 max_retries: 3
 delay_milliseconds: 500
 retry_on_status_codes:
 - 500
 - 502
 - 503

 cache:
 enabled: true
 ttl_seconds: 120

 chaos:
 enabled: false
 injection_rate_percentage: 33
 delay_milliseconds: 200
 simulate_status_code: 503
 simulate_network_exception: false

 mock:
 enabled: false
 status_code: 200
 headers:
 Content-Type: 'application/json'
 body: '{ "result": "mocked" }'

Loading config

Three loaders are available on YamlHttpClientConfigBuilder:

// From a file path
var settings = new YamlHttpClientConfigBuilder().LoadFromFile("config.yml", "myHttpCall");

// From a YAML string (e.g. loaded from a database or environment variable)
var settings = new YamlHttpClientConfigBuilder().LoadFromString(yamlString, "myHttpCall");

// From a byte array (e.g. embedded resource)
var settings = new YamlHttpClientConfigBuilder().LoadFromBytes(yamlBytes, "myHttpCall");

var httpClient = new YamlHttpClientFactory(settings);

Dependency injection

// Startup / Program.cs
services.AddYamlHttpClientAccessor();

// In your service
public class MyService
{
 private readonly IYamlHttpClientAccessor _client;

 public MyService(IYamlHttpClientAccessor client)
 {
 _client = client;
 _client.HttpClientSettings = new YamlHttpClientConfigBuilder()
 .LoadFromFile("config.yml", "myHttpCall");
 _client.HandlebarsProvider = YamlHttpClientFactory.CreateDefaultHandleBars();
 }

 public async Task<string> CallAsync(object data)
 {
 var response = await _client.AutoCallAsync(data);
 await _client.CheckResponseAsync(response);
 return await response.Content.ReadAsStringAsync();
 }
}

AutoCallAsync

AutoCallAsync is a convenience method that wraps BuildRequestMessage + SendAsync(Func<HttpRequestMessage>) in a single call. It integrates with the retry and cache pipelines automatically.

// Without cancellation token
var response = await httpClient.AutoCallAsync(myData);

// With cancellation token
var response = await httpClient.AutoCallAsync(myData, cancellationToken);

Use AutoCallAsync instead of BuildRequestMessage + SendAsync whenever you want retry and cache to work together correctly — the factory-based overload of SendAsync is required for those features.


Retry

Retry is configured per HTTP client in YAML. The engine retries on specified HTTP status codes and on transient network exceptions (HttpRequestException, timeout).

http_client:
 myHttpCall:
 method: GET
 url: https://api.example.com/data
 retry:
 max_retries: 3 # Number of retries after the initial attempt
 delay_milliseconds: 500 # Wait between attempts
 retry_on_status_codes: # Only retry on these codes; omit to retry only on exceptions
 - 500
 - 502
 - 503
 - 504
var settings = new YamlHttpClientConfigBuilder().LoadFromString(yaml, "myHttpCall");
var httpClient = new YamlHttpClientFactory(settings);

// AutoCallAsync handles retries transparently
var response = await httpClient.AutoCallAsync(myData);

Cache

Responses are cached in memory keyed by Method + URL + body hash. Only successful responses (2xx) are cached. The cache is shared across all instances for the same URL.

http_client:
 myHttpCall:
 method: GET
 url: https://api.example.com/reference-data
 cache:
 enabled: true
 ttl_seconds: 600 # 10 minutes; default is 600
var settings = new YamlHttpClientConfigBuilder().LoadFromString(yaml, "myHttpCall");
var httpClient = new YamlHttpClientFactory(settings);

// First call hits the network; subsequent identical calls return from cache
var response = await httpClient.AutoCallAsync(myData);

Cache and retry work together: the cache is checked before the retry loop, and a successful retry response is stored in cache.


Chaos Monkey

Chaos Monkey injects failures into your HTTP calls at a configurable rate. This is useful for testing resilience locally or in a staging environment without needing an unstable external service.

http_client:
 myHttpCall:
 method: POST
 url: https://api.example.com/endpoint
 chaos:
 enabled: true
 injection_rate_percentage: 30 # 30% of calls will be affected
 delay_milliseconds: 300 # Always add 300ms delay (regardless of injection rate)
 simulate_status_code: 503 # Return a fake 503 on affected calls
 # simulate_network_exception: true # Throw HttpRequestException instead

The three chaos modes (combinable):

Option Effect
delay_milliseconds Adds a fixed delay to every call
simulate_status_code Returns a fake HTTP response with that status code
simulate_network_exception: true Throws an HttpRequestException (simulates DNS failure, connection reset, etc.)

simulate_status_code and simulate_network_exception are only triggered when a call falls within the injection_rate_percentage. delay_milliseconds is always applied when set.

// Chaos is fully transparent to calling code — no changes needed
var response = await httpClient.AutoCallAsync(myData);

Combining chaos with retry lets you verify your retry policy actually recovers from failures:

http_client:
 myHttpCall:
 method: GET
 url: https://api.example.com/data
 chaos:
 enabled: true
 injection_rate_percentage: 50
 simulate_status_code: 503
 retry:
 max_retries: 3
 delay_milliseconds: 100
 retry_on_status_codes:
 - 503

Mock

Mock lets you return a predefined HTTP response directly from the YAML configuration, without making any real network call. This is useful during development, integration testing, or when an external API is not yet available.

http_client:
 myMockedCall:
 method: GET
 url: https://api.example.com/users
 mock:
 enabled: true
 status_code: 200
 headers:
 Content-Type: 'application/json'
 X-Custom-Header: 'mock-value'
 body: |
 {
 "users": [
 { "id": 1, "name": "Alice" },
 { "id": 2, "name": "Bob" }
 ]
 }

When mock.enabled is true, calling AutoCallAsync or SendAsync skips the HTTP call entirely and returns a fabricated HttpResponseMessage with the specified status code, headers, and body.

Option Default Description
enabled false Enables or disables the mock response
status_code 200 The HTTP status code to return
headers (none) Response headers to include
body (empty) The response body content
var settings = new YamlHttpClientConfigBuilder().LoadFromFile("config.yml", "myMockedCall");
var httpClient = new YamlHttpClientFactory(settings);

// No network call is made — the mock response is returned immediately
var response = await httpClient.AutoCallAsync(myData);
var content = await response.Content.ReadAsStringAsync();
// content = { "users": [ { "id": 1, "name": "Alice" }, ... ] }

Mock works seamlessly with check_response, so you can validate your mock responses against the same rules used in production:

http_client:
 myMockedCall:
 method: GET
 url: https://api.example.com/users
 mock:
 enabled: true
 status_code: 200
 body: '{ "status": "success", "data": [] }'
 check_response:
 throw_exception_if_body_not_contains_all:
 - success

Mock can also be combined with the orchestrator — individual steps in a pipeline can be mocked independently, which is useful when only some external APIs are available:

http_client_set:
 user_pipeline:
 sequence:
 - http_client: get_token
 - http_client: get_users

http_client:
 get_token:
 method: POST
 url: https://auth.example.com/token
 mock:
 enabled: true
 status_code: 200
 body: '{ "access_token": "fake-token-for-dev" }'

 get_users:
 method: GET
 url: https://api.example.com/users
 headers:
 Authorization: 'Bearer {{get_token.body.access_token}}'

Tip: Use mock to prototype your YAML pipelines before the real APIs are deployed. Once ready, simply set mock.enabled: false (or remove the mock block) to switch to live calls.


Orchestrator

YamlHttpOrchestrator (requires .NET 6+) executes named pipelines defined in http_client_set. Each pipeline runs an ordered sequence of HTTP calls; every step's response is aggregated and made available to subsequent steps and to the final data_adapter template via Handlebars.

YAML config

A single YAML file contains both http_client_set (the pipelines) and http_client (the individual client definitions). Each pipeline references its clients by name and defines its own data_adapter output template.

http_client_set:
 users:
 sequence:
 - http_client: get_token
 - http_client: get_users
 as: get_users # optional alias; defaults to http_client name
 data_adapter:
 template: |
 {
 "count": {{get_users.body.total}},
 "items": {{{Json get_users.body.records}}}
 }

 user_orders:
 sequence:
 - http_client: get_token
 - http_client: get_user
 - http_client: get_orders
 data_adapter:
 template: |
 {
 "customer": "{{get_user.body.name}}",
 "email": "{{get_user.body.email}}",
 "orders": {{{Json get_orders.body.records}}}
 }

http_client:
 get_token:
 method: POST
 url: https://auth.example.com/token
 content:
 json_content: |
 { "client_id": "{{input.clientId}}", "client_secret": "{{input.secret}}" }

 get_users:
 method: GET
 url: https://api.example.com/users
 headers:
 Authorization: 'Bearer {{get_token.body.access_token}}'
 Accept: 'application/json'
 retry:
 max_retries: 2
 delay_milliseconds: 500
 retry_on_status_codes: [500, 502, 503]
 chaos:
 enabled: false
 injection_rate_percentage: 50
 simulate_status_code: 500

 get_user:
 method: GET
 url: 'https://api.example.com/users/{{input.userId}}'
 headers:
 Authorization: 'Bearer {{get_token.body.access_token}}'
 Accept: 'application/json'

 get_orders:
 method: GET
 # References input data and a previous step's response
 url: 'https://api.example.com/orders?userId={{get_user.body.id}}'
 headers:
 Authorization: 'Bearer {{get_token.body.access_token}}'
 Accept: 'application/json'

If data_adapter.template is omitted or blank, ExecuteSetAsync returns the full aggregated data object as raw JSON.

Data model inside templates

After each step completes, its result is added to the aggregated data object under its alias (defaulting to the http_client name). The full shape available in any template is:

{
 input: { ...your inputData... },
 get_token: { body: {...}, headers: {...}, url: "https://..." },
 get_user: { body: {...}, headers: {...}, url: "https://..." },
 get_orders: { body: {...}, headers: {...}, url: "https://..." }
}

Both url fields in http_client definitions and data_adapter templates have full access to this object via Handlebars.

C# usage — ExecuteSetAsync

The preferred entry point. Loads the pipeline and all client definitions directly from the parsed config:

using YamlHttpClient;
using YamlHttpClient.Settings;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

// Parse the full YAML config (both http_client_set and http_client)
var yaml = File.ReadAllText("pipeline.yml");
var config = new DeserializerBuilder()
 .WithNamingConvention(NullNamingConvention.Instance)
 .IgnoreUnmatchedProperties()
 .Build()
 .Deserialize<YamlHttpClientConfigBuilder>(yaml);

var handlebars = YamlHttpClientFactory.CreateDefaultHandleBars();
var orchestrator = new YamlHttpOrchestrator(handlebars);

// Execute a named pipeline by key
var result = await orchestrator.ExecuteSetAsync(
 setName: "regions",
 config: config,
 inputData: new { clientId = "my-app", secret = "s3cr3t" },
 defaultHttpTimeout: TimeSpan.FromSeconds(30),
 ct: CancellationToken.None
);

Console.WriteLine(result);

// Inspect which URLs were actually called
foreach (var url in orchestrator.LastCalledUrls)
 Console.WriteLine($"Called: {url}");

C# usage — ExecuteSequenceAsync (advanced)

Use this overload when the sequence and data adapter template are defined in C# rather than in YAML:

var steps = new List<dynamic>
{
 new { HttpClient = "get_token", As = "get_token" },
 new { HttpClient = "get_regions", As = "get_regions" }
};

var result = await orchestrator.ExecuteSequenceAsync(
 inputData: new { clientId = "my-app", secret = "s3cr3t" },
 sequenceAppels: steps,
 dictClientsConfig: config.HttpClient,
 dataAdapterTemplate: "{{get_regions.body.result.records}}",
 defaultHttpTimeout: TimeSpan.FromSeconds(30),
 ct: CancellationToken.None
);

Default options

YamlHttpOrchestratorOptions provides fallback cache and retry settings applied to any step that does not define its own:

Option Default
DefaultCacheSettings.Enabled true
DefaultCacheSettings.TtlSeconds 1200 (20 min)
DefaultRetrySettings.MaxRetries 3
DefaultRetrySettings.RetryOnStatusCodes 500, 501, 502, 503, 504

Pass null for options to use these defaults, or override selectively.


Handlebars helpers

All templates (URL, headers, body, data adapter) are processed with Handlebars.Net.

{{{Json VAR}}}

Serializes a variable to JSON.

{{{Json obj}}} → {"test":1}
{{{Json obj ">forcestring"}}} → "{\"test\":1}"
{{{Json val1 val2}}} → "concatenated strings"

{{{Json VAR ">flatten;SEP;IDX"}}}

Flattens a nested object to a single-level dictionary.

{{{Json . ">flatten;.;[{0}]"}}} → {"obj[0].test":1,"obj[1].test":2}
{{{Json . ">flatten;_;_{0}"}}} → {"obj_0_test":1,"obj_1_test":2}
{{{Json . ">flatten;_;_{0}" ">forcestring"}}} → {"obj_0_test":"1","obj_1_test":"2"}

{{#ifCond A OP B}}

Conditional block helper. Supported operators: =, ==, !=, <>, <, >, contains, in.

{{#ifCond status '=' 'active'}}Active{{else}}Inactive{{/ifCond}}
{{#ifCond roles 'contains' 'admin'}}Has admin{{/ifCond}}

{{{Base64 VAR}}}

Encodes an object or image to Base64.

{{{Base64 myObject}}}

Template caching

Templates are compiled once and cached automatically via CompileWithCache. Call HandleBarsExtensions.ClearTemplateCache() if you need to reload templates at runtime (e.g. hot reload of YAML config).


Features checklist

  • ✅ All HTTP methods (GET, POST, PUT, DELETE, PATCH...)
  • ✅ Any request headers with Handlebars templating
  • ✅ JSON, string, form data and binary (Base64) content types
  • ✅ Basic HTTP authentication
  • ✅ NTLM authentication (app pool auto-negotiation)
  • ✅ Response validation with configurable rules (check_response)
  • ✅ Automatic retry with configurable status codes and delay
  • ✅ In-memory response cache with TTL
  • ✅ Chaos Monkey (delay, fake status code, network exception simulation)
  • ✅ Mock responses (return predefined responses without network calls)
  • ✅ Multi-step HTTP orchestration with data aggregation (YamlHttpOrchestrator, .NET 6+)
  • ✅ Dependency injection support (IYamlHttpClientAccessor)
  • ⬜ NTLM with explicit user/password
  • ⬜ Client certificate authentication
Product Versions Compatible and additional computed target framework versions.
.NET net5.0 net5.0 is compatible.  net5.0-windows net5.0-windows was computed.  net6.0 net6.0 is compatible.  net6.0-android net6.0-android was computed.  net6.0-ios net6.0-ios was computed.  net6.0-maccatalyst net6.0-maccatalyst was computed.  net6.0-macos net6.0-macos was computed.  net6.0-tvos net6.0-tvos was computed.  net6.0-windows net6.0-windows was computed.  net7.0 net7.0 is compatible.  net7.0-android net7.0-android was computed.  net7.0-ios net7.0-ios was computed.  net7.0-maccatalyst net7.0-maccatalyst was computed.  net7.0-macos net7.0-macos was computed.  net7.0-tvos net7.0-tvos was computed.  net7.0-windows net7.0-windows was computed.  net8.0 net8.0 is compatible.  net8.0-android net8.0-android was computed.  net8.0-browser net8.0-browser was computed.  net8.0-ios net8.0-ios was computed.  net8.0-maccatalyst net8.0-maccatalyst was computed.  net8.0-macos net8.0-macos was computed.  net8.0-tvos net8.0-tvos was computed.  net8.0-windows net8.0-windows was computed.  net9.0 net9.0 was computed.  net9.0-android net9.0-android was computed.  net9.0-browser net9.0-browser was computed.  net9.0-ios net9.0-ios was computed.  net9.0-maccatalyst net9.0-maccatalyst was computed.  net9.0-macos net9.0-macos was computed.  net9.0-tvos net9.0-tvos was computed.  net9.0-windows net9.0-windows was computed.  net10.0 net10.0 is compatible.  net10.0-android net10.0-android was computed.  net10.0-browser net10.0-browser was computed.  net10.0-ios net10.0-ios was computed.  net10.0-maccatalyst net10.0-maccatalyst was computed.  net10.0-macos net10.0-macos was computed.  net10.0-tvos net10.0-tvos was computed.  net10.0-windows net10.0-windows was computed. 
.NET Core netcoreapp3.1 netcoreapp3.1 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.1 133 3/18/2026
2.1.0 158 3/16/2026
2.1.0-rc1 138 3/15/2026
2.0.0 151 3/12/2026
2.0.0-rc5 136 3/12/2026
2.0.0-rc4 137 3/12/2026
2.0.0-rc3 144 3/12/2026
2.0.0-rc2 103 3/9/2026
2.0.0-rc1 114 3/9/2026
1.0.8 700 6/16/2025
1.0.7 251 12/23/2024
1.0.6 672 9/17/2024
1.0.5 280 9/15/2023
1.0.4 237 9/15/2023
1.0.3 213 9/15/2023
1.0.2 361 3/15/2023
1.0.1 852 3/29/2022
Loading failed