Recap of JSON Patch
As discussed in a past article, a JSON patch is a format specifier that describes a sequence of operations in a JSON document. This document contains a structured and efficient approach to perform partial updates to a JSON object.
Advantages:
Efficient
Precision
Scalability
Disadvantages:
Complexity
Error-prone
Security concerns
Introducing JSON Patch Validation
JSON patch validation involves checking the correctness and applicability of the patch operations before they are executed on the JSON document. The aim is to ensure the operations are valid according to the document's schema, preventing errors and potential security risks, like unintended data exposure or corruption.
Advantages:
Data integrity
Error handling
Improving security
Disadvantages:
Additional processes
Complex implementation
Maintenance
Understanding How JSON Patch Validation Works
JSON Validation is vital to understand, as improper implementation will compromise data integrity and security. The JSON patch validates differently from regular requests by testing the following:
Syntax
Semantic
Business logic
The syntax of the JSON Patch document is validated against patch specification, including correct values and appropriate fields for each operation.
The semantics are validated by applying the patch to a temporary copy of the JSON document to ensure that operations succeed without errors.
JSON patch also supports custom business logic validation like regular request validations, ensuring that the patch operations comply with business rules.
Implementing JSON Patch Validation
Last week, we investigated data validation and the business logic of regular requests when creating a user. This week, we will investigate partial updates with JSON patches and how validation is applied when modifying user information.
The PartialUpdateUser
class above represents a request to update the existing user details. It implements the IRequest<GetUserResponse>
interface from MediatR to expect a return type of GetUserResponse
from the handler. The class handles the partial modification through the Payload
, a JsonPatchDocument<PartialUserModel>
. This allows the client to specify patch operations to modify certain attributes within the PartialUserModel
. The request asks for the UserId
to obtain the user whose data is being modified. The Payload
will accept data modification according to the PartialUserModel
.
The code snapshot above is the PartialUpdateUservalidator
, which inherits from the AbstractValidator
and takes PartialUpdateUser
as the type. This means that the validator will assess instances of PartialUpdateUser
according to the specified rules. The PartialUpdateUserValidator()
constructor injects instances of RosterContext
and PartialUserModelValidator
to this validator. The rules set are UserId
must be greater than 0 & must exist in the database. It tests the Payload
information using a boolean method called IsPayloadValid
. The method obtains the user's data from the database through the UserId
. It loads the information into a temporary PartialUserModel
and applies the changes before validating. If the model is valid, it returns true
; otherwise, it returns identified errors in the model and returns false
. If any exceptions occur during the patching or validation, they are caught, and a false
is returned, indicating that the Payload
has not been validated successfully. Finally, the code calls the PartialUserModelValidator
to assess if the requests adhere to the specified format rules.
The CascadeMode.stop
will stop the subsequent rules in the same chain from executing if one rule fails. For instance, if FirstName
is empty, it won't test if it Matches
the specified format. Additionally, the attributes must match a specific format, as those fields cannot contain numbers and special symbols, only letters.
As mentioned above, the handler will apply modification to the user and return the response. The handler can access the database through the injected instance of the RostersContext
, which allows it to retrieve the user information provided in the request. The user information is loaded in a temporary model of PartialUserModel
, and modifications are applied to the model. It then updates the user entity in the database with the new values and saves the changes asynchronously. Finally, it returns a response containing the updated user details, effectively allowing for dynamic, partial updates to user records based on JSON patch operations.
The validator and handler codes for partial updates are very similar, and the only difference between them is the validator assesses the data before passing it to the handler. If the validator were absent in the code, the handler would apply changes as requested without determining if the data is valid or adheres to business logic.
Testing Validations
Let's test the validations we implemented; here is a snapshot of my records in the database.
So here I will test the UserId
greater than 0 and must exist. These are my requests.
And here are my responses below.
Now, let's test my existing records.
Here are the responses:
Let us try something valid now:
Here is the response:
Let us check if it is updated in the database:
Conclusion
This week, we delved into the sophisticated realm of JSON Patch validation, a crucial process that ensures the integrity and applicability of modifications to JSON documents. By implementing JSON Patch, developers can perform efficient, precise, and scalable updates, explicitly targeting the parts of a document that need change without affecting the whole. However, this method is not without challenges; it introduces complexity, is prone to errors, and raises security concerns if not implemented correctly. The validation process checks syntax, semantics, and compliance with business logic to ensure that every operation is executed efficiently and securely. Through demonstrations in a .NET environment, we have illustrated how JSON Patch operations allow for dynamic partial updates to user records, enhancing functionality and security by catching errors and enforcing business rules before database modifications are applied. This approach maintains data integrity and fortifies the application against potential vulnerabilities.