Releases: anvilco/dotnet-anvil
v0.6.0
0.6.0
Breaking Changes
GraphQL errors now throw AnvilClientException
Previously, HTTP-level errors from the GraphQL client threw GraphQLHttpRequestException. They now throw AnvilClientException with the original preserved as InnerException.
Before:
try
{
var result = await graphqlClient.SendQuery(query, variables);
}
catch (GraphQLHttpRequestException ex)
{
// handle error
}After:
try
{
var result = await graphqlClient.SendQuery(query, variables);
}
catch (AnvilClientException ex)
{
Console.WriteLine(ex.HttpStatusCode); // e.g. 429
Console.WriteLine(ex.ResponseContent); // raw response body
Console.WriteLine(ex.ResponseHeaders); // dictionary of headers
Console.WriteLine(ex.InnerException); // original GraphQLHttpRequestException
}SendGetRequest now throws on error responses
Previously, SendGetRequest silently returned failed HttpResponseMessage objects without throwing. It now throws AnvilClientException, consistent with SendPostRequest. This affects DownloadDocuments and any direct calls to SendGetRequest.
Before:
var response = await restClient.SendGetRequest(uri);
if (!response.IsSuccessStatusCode) { /* manual check */ }After:
try
{
var response = await restClient.SendGetRequest(uri);
}
catch (AnvilClientException ex)
{
// error details available on ex
}GraphQL error message format changed
Multiple GraphQL errors are now joined with "; " instead of concatenated directly.
Before: "Field required""Email invalid"
After: "Field required; Email invalid"
Individual messages are also available via ex.Data["Message1"], ex.Data["Message2"], etc.
Target framework simplified
The library now targets netstandard2.0 only, replacing net5.0;netstandard2.0;net461. Since netstandard2.0 is compatible with .NET Framework 4.6.1+, .NET Core 2+, and all modern .NET versions, most consumers are unaffected. Consumers that pinned to net5.0 or net461 should verify compatibility.
New Features
AnvilClientException properties
All error paths now populate these properties:
| Property | Type | Description |
|---|---|---|
HttpStatusCode |
HttpStatusCode? |
The HTTP status code (e.g. 429, 401, 500) |
ResponseHeaders |
Dictionary<string, IEnumerable<string>>? |
Response headers (case-insensitive lookup) |
ResponseContent |
string? |
Raw response body |
InnerException |
Exception? |
Original exception (GraphQL path only) |
Data["Message1"], etc. |
object? |
Individual error messages from the API |
IDisposable support
RestClient and GraphQLClient now implement IDisposable to clean up their underlying HttpClient. Existing code that doesn't call Dispose() will continue to work.
using var client = new RestClient("your-api-key");Bug Fixes
- Non-JSON error responses no longer crash the client. Both REST and GraphQL paths now catch
JsonExceptionand fall back gracefully, preserving the raw response content on the exception. RestClient.CreateExceptionFromResponseis now async. The previous implementation used.Resultto block onReadAsStringAsync(), which could deadlock in synchronous contexts or UI threads.EtchSigner.SignerTypeno longer throwsNullReferenceExceptionon null input.DocumentMarkup.MarkupandHtmlCssMarkup.Htmlnullable annotations fixed. These properties were annotated as non-nullable but could be null after JSON deserialization.- Error messages with null
messagefields are now skipped. Previously, JSON error entries without amessagekey would insertnullvalues into the exception'sDatadictionary.
Dependencies
- Upgraded
Newtonsoft.Jsonfrom 12.0.3 to 13.0.3 to resolve a high-severity vulnerability (GHSA-5crp-9r3c-p9vr).
Internal
- Added GitHub Actions CI workflow (build, format check, tests on PRs to main).
- Test project updated to target
net10.0. InternalsVisibleToadded to support unit testing of internal error-wrapping logic.WrapGraphQLExceptionextracted as aninternal staticmethod fromSendQuery<T>to make GraphQL error-wrapping logic unit-testable without mocking HTTP calls.ResponseHeadersdictionaries useStringComparer.OrdinalIgnoreCasein both REST and GraphQL paths, since HTTP headers are case-insensitive.- Fixes #17