ResQueServe moves beyond simple HTTP Status Codes (like 404 or 500) to provide rich, machine-readable debugging context. We strictly adhere to the RFC 7807 (Problem Details for HTTP APIs) standard.
When an API request fails, the server returns a structured JSON document known as a "Problem Detail". This document tells you not just that an error occurred, but why, where, and how to fix it.
Anatomy of a Failure Response
If you inspect the raw HTTP response of a failed request (e.g., trying to create a Unit with a duplicate Callsign), you will see a payload like this:
JSON
{
"title": "The request was invalid.",
"status": 400,
"detail": "Invalid value for property 'CallNumberEmergency'. Provided: '911-better-call-saul'.",
"instance": "/api/v1/info/system",
"traceIdentifier": "0HNIFIC46DOJN:00000001",
"exceptionType": "XENBIT.ResQueServe.Core.Exceptions.InvalidValueException",
"exception": {
"invalidProperty": "CallNumberEmergency",
"providedValue": "911-better-call-saul",
"message": "Invalid value for property 'CallNumberEmergency'. Provided: '911-better-call-saul'.",
"problems": [76]
},
"cooked": ["Das Format der Notrufnummer der Leitstelle ist ungültig."]
}traceIdentifier: A unique ID for the specific request. Always log this. It is the primary key our support team uses to look up server-side logs.cooked: An array of human-readable, pre-localized strings. These are safe to display directly to an end-user (e.g., in a Toast notification).problems: An array of integer codes corresponding to theProblemInformationenum. This allows your code to react programmatically to specific errors without parsing text.exceptionType: The fully qualified name of the server-side exception.
SDK Exception Hierarchy
The ResQueServe SDK (XENBIT.ResQueServe.SDK) automatically intercepts these JSON responses and deserializes them into strongly-typed C# exceptions. All platform-specific exceptions inherit from the base class ResQueServeException. This allows you to write a single catch block for general error handling, or specific blocks for granular control.
Core Exception Types
Exception Class | HTTP Status | Trigger Condition | Key Properties |
| 404 | You requested a resource ID that doesn't exist, or a referenced parent (like a Station) is missing. |
|
| 409 | A unique constraint was violated (e.g., creating two units with the same Callsign). |
|
| 400 | The data violates business rules (e.g., assigning a Helicopter to a Hospital that has no helipad). |
|
| 400 | A required field (like |
|
| 400 | Data format is wrong (e.g., invalid Regex for a Callsign, or coordinates out of range). |
|
| 500 / Other | Something unexpected happened (Network failure, Serialization error, or unmapped API error). |
|
The ProblemInformation Enum Strategy
While exception types give you the category of error, the ProblemInformation enum gives you the specific cause. This is critical for building robust integrations that can self-correct or guide the user. These enums are defined in XENBIT.ResQueServe.Abstractions.DataStructure.
Practical Implementation Patterns
Do not rely on try/catch (Exception ex). That is too generic. Below is the recommended pattern for a production-grade integration.
Scenario: Creating a New Unit
This example attempts to create a unit and handles specific edge cases like "Station not found" or "Duplicate Callsign" distinct from a general crash.
C#
using XENBIT.ResQueServe.Abstractions.DataStructures;
using XENBIT.ResQueServe.Core.Exceptions;
using XENBIT.ResQueServe.Abstractions.Exceptions;
public async Task SafeCreateUnit(long dpcId, IUnit newUnit)
{
try
{
var result = await _unitClient.CreateAsync(dpcId, newUnit);
Console.WriteLine($"Success! Unit created with ID {result.Id}");
}
// 1. Handle "Missing Data" specifically
catch (DataNotFoundException ex)
{
// Example: The POI ID provided for the station doesn't exist
if (ex.LookupProperty == "Poi")
{
Console.WriteLine($"Error: The Station ID {ex.ProvidedValue} does not exist.");
}
else
{
Console.WriteLine($"Error: {ex.Message}");
}
}
// 2. Handle "Validation Rules"
catch (ValidationException ex)
{
// Check for specific logic problems using the Enum
if (ex.Problems.Contains(ProblemInformation.CallsignAlreadyExists))
{
Console.WriteLine("That callsign is taken. Please generate a new one.");
}
else if (ex.Problems.Contains(ProblemInformation.UnitStationPoiIsRequired))
{
Console.WriteLine("You forgot to assign a Home Station.");
}
else
{
// Fallback: Show the server's human-readable messages
// The 'Cooked' property is not on the Exception directly, but usually
// the Message property of these exceptions is composed of the title.
// For full access to 'Cooked', we check the inner ProblemDetails if exposed.
Console.WriteLine("Validation Failed: " + ex.Message);
}
}
// 3. Handle Formatting/Regex errors
catch (InvalidValueException ex)
{
Console.WriteLine($"The value '{ex.ProvidedValue}' is invalid for field '{ex.InvalidProperty}'.");
}
// 4. Catch-all for Platform Errors
catch (ResQueServeException ex)
{
// LOGGING THE TRACE ID IS CRITICAL
// It's usually inside the Problems array or the inner ProblemDetails
var traceId = ex.Problems?.FirstOrDefault().ToString() ?? "N/A";
_logger.LogError(ex, "Platform Error. TraceId: {TraceId}", traceId);
}
}
Frontend & UI Integration
If you are building a UI (Blazor, WPF, or MVC) that consumes the SDK, the exceptions include a helper method HandleDispatcherExceptionOnFrontend. While this is primarily for internal internal views, the ProblemDetails.Cooked property is designed for you.
Example: Displaying errors in a UI
When you catch a ResQueServeException, you should look at the internal ProblemDetails.
C#
catch (ResQueServeException ex) when (ex is UnknownException unknownEx)
{
// UnknownException wraps the raw ProblemDetails
if (unknownEx.ProblemDetails?.Cooked != null)
{
foreach (var userMessage in unknownEx.ProblemDetails.Cooked)
{
MyToastService.ShowError(userMessage);
}
}
}
Debugging & Support
When reporting an issue to ResQueServe support, "It didn't work" is rarely enough. Because our system is distributed, we rely on the Trace Identifier.
Catch
ResQueServeException.Inspect the JSON response (or the Exception properties).
Extract the
traceIdentifier(e.g.,00-8432b7a1...).Send this ID along with the timestamp to developer support.
This ID allows us to replay the exact request context in our distributed logs to see exactly why the validation logic rejected your specific payload.
