diff --git a/Core/CommandQueries/CommandResponse.cs b/Core/CommandQueries/CommandResponse.cs
index 1b0bac7..52dd0f5 100644
--- a/Core/CommandQueries/CommandResponse.cs
+++ b/Core/CommandQueries/CommandResponse.cs
@@ -1,16 +1,43 @@
-namespace PlanTempus.Core.CommandQueries;
+
+namespace PlanTempus.Core.CommandQueries;
-public class CommandResponse
+///
+/// Represents a response to a command request, typically used in asynchronous operations.
+/// This class includes details such as a unique request ID, correlation ID, command name,
+/// transaction ID, creation timestamp, and a URL to check the status of the command.
+///
+/// A unique identifier used to track the request across services.
+/// The name of the command being executed.
+/// An optional unique identifier for the transaction associated with the command.
+public class CommandResponse(Guid correlationId, string commandName, Guid? transactionId)
{
- public Guid RequestId { get; }
- public Guid CorrelationId { get; }
- public Guid? TransactionId { get; }
- public DateTime CreatedAt { get; }
+ ///
+ /// A unique identifier for the request. This is automatically generated using Guid.CreateVersion7().
+ ///
+ public Guid RequestId { get; } = Guid.CreateVersion7();
- public CommandResponse(Guid correlationId)
- {
- CorrelationId = correlationId;
- RequestId = Guid.CreateVersion7();
- CreatedAt = DateTime.Now;
- }
+ ///
+ /// A unique identifier used to track the request across services. This is provided when creating the response.
+ ///
+ public Guid CorrelationId { get; } = correlationId;
+
+ ///
+ /// The name of the command being executed.
+ ///
+ public string CommandName { get; } = commandName;
+
+ ///
+ /// An optional unique identifier for the transaction associated with the command.
+ ///
+ public Guid? TransactionId { get; } = transactionId;
+
+ ///
+ /// The timestamp when the command response was created. This is automatically set to the current UTC time.
+ ///
+ public DateTime CreatedAt { get; } = DateTime.UtcNow;
+
+ ///
+ /// A URL where the client can check the status of the command. This is typically used in asynchronous operations.
+ ///
+ public string StatusUrl { get; } = "statusUrl";
}
\ No newline at end of file
diff --git a/Core/CommandQueries/ProblemDetails.cs b/Core/CommandQueries/ProblemDetails.cs
new file mode 100644
index 0000000..7e2f6d9
--- /dev/null
+++ b/Core/CommandQueries/ProblemDetails.cs
@@ -0,0 +1,56 @@
+namespace PlanTempus.Core.CommandQueries;
+
+///
+/// Represents a standardized error response according to RFC 9457 (Problem Details for HTTP APIs).
+/// This class provides a consistent way to communicate errors in HTTP APIs, including details about the error type,
+/// status code, and additional context. It also supports extensions for custom error information.
+///
+/// RFC 9457 Documentation: https://www.rfc-editor.org/rfc/rfc9457.html
+///
+public class ProblemDetails
+{
+ ///
+ /// A URI reference that identifies the problem type. This is typically a link to human-readable documentation about the error.
+ ///
+ public string Type { get; set; }
+
+ ///
+ /// A short, human-readable summary of the problem. It should not change between occurrences of the same error.
+ ///
+ public string Title { get; set; }
+
+ ///
+ /// The HTTP status code generated by the server for this occurrence of the problem. This allows the client to understand the general category of the error.
+ ///
+ public int? Status { get; set; }
+
+ ///
+ /// A human-readable explanation specific to this occurrence of the problem. It provides additional details about the error.
+ ///
+ public string Detail { get; set; }
+
+ ///
+ /// A URI reference that identifies the specific occurrence of the problem. This can be used to trace the error in logs or debugging tools.
+ ///
+ public string Instance { get; set; }
+
+ ///
+ /// A dictionary for additional, custom error information. This allows extending the problem details with application-specific fields.
+ ///
+ [Newtonsoft.Json.JsonExtensionData]
+ public Dictionary Extensions { get; } = new();
+
+ ///
+ /// Adds a custom extension to the problem details.
+ ///
+ /// The key for the extension.
+ /// The value of the extension.
+ public void AddExtension(string key, object value) => Extensions.Add(key, value);
+
+
+ ///
+ /// Removes a custom extension from the problem details.
+ ///
+ /// The key of the extension to remove.
+ public void RemoveExtension(string key) => Extensions.Remove(key);
+}
\ No newline at end of file
diff --git a/PlanTempus.Components/Users/Create/CreateUserHandler.cs b/PlanTempus.Components/Users/Create/CreateUserHandler.cs
index 651f899..d5acd1c 100644
--- a/PlanTempus.Components/Users/Create/CreateUserHandler.cs
+++ b/PlanTempus.Components/Users/Create/CreateUserHandler.cs
@@ -36,10 +36,7 @@ namespace PlanTempus.Components.Users.Create
command.IsActive,
});
-
- var result = data.First();
-
- return new CommandResponse(command.CorrelationId);
+ return new CommandResponse(command.CorrelationId, command.GetType().Name, command.TransactionId);
}
catch (PostgresException ex) when (ex.SqlState == "23505")
{
diff --git a/Tests/CommandQueryHandlerTests/ResponseTests.cs b/Tests/CommandQueryHandlerTests/ResponseTests.cs
new file mode 100644
index 0000000..d808f12
--- /dev/null
+++ b/Tests/CommandQueryHandlerTests/ResponseTests.cs
@@ -0,0 +1,53 @@
+using Newtonsoft.Json;
+using PlanTempus.Core.CommandQueries;
+using Shouldly;
+
+namespace PlanTempus.X.TDD.CommandQueryHandlerTests;
+
+[TestClass]
+public class ProblemDetailsTests
+{
+ [TestMethod]
+ public void TestFormatOfProblemDetails()
+ {
+ // Arrange
+ var problemDetails = new ProblemDetails
+ {
+ Type = "https://example.com/errors/invalid-input",
+ Title = "Invalid Input",
+ Status = 400,
+ Detail = "The request body is invalid.",
+ Instance = "/api/users"
+ };
+
+ problemDetails.AddExtension("invalidFields", new[]
+ {
+ new { Field = "name", Message = "The 'name' field is required." },
+ new { Field = "email", Message = "The 'email' field must be a valid email address." }
+ });
+
+ var json = JsonConvert.SerializeObject(problemDetails, Formatting.Indented);
+
+ var expectedJson = """
+ {
+ "Type": "https://example.com/errors/invalid-input",
+ "Title": "Invalid Input",
+ "Status": 400,
+ "Detail": "The request body is invalid.",
+ "Instance": "/api/users",
+ "invalidFields": [
+ {
+ "Field": "name",
+ "Message": "The 'name' field is required."
+ },
+ {
+ "Field": "email",
+ "Message": "The 'email' field must be a valid email address."
+ }
+ ]
+ }
+ """;
+
+ json.ShouldBe(expectedJson);
+ }
+}
\ No newline at end of file