A library to apply JSON patches with rule-based access control.
Project description
python-json-patch-rules
Json Patch Rules is a Python library designed to facilitate the application of JSON patch operations while enforcing customizable validation rules. This library ensures that updates to JSON objects adhere to predefined permissions, making it ideal for systems that require granular access control.
Features
- Rule-Based Validation: Define rules that specify which paths in a JSON object are allowed to be updated.
- Wildcard Support: Use wildcards to specify rules for dynamic keys and array indices.
- Data Integrity: Ensure that only permitted paths can be updated, preserving the integrity of the JSON structure.
Installation
Install Json Patch Rules using pip:
pip install python-json-patch-rules
API
Rule | Description |
---|---|
{*} |
Implicit set - allows to set new attributes but not remove them. |
!{*} |
Implicit set - denies the ability to set new attributes. |
[0] |
Implicit set - allows replacing index "0" with any value (string, object, int, etc). |
[0]|replace |
Allows replacing index "0" with any value (string, object, int, etc). |
[*]|unique |
Allows replacing an array but denies if there are duplicated items (works only for arrays of strings). |
user |
Allows setting value to user property (must be an object at root level). |
!user |
Denies setting value to user property (must be an object at root level). |
[0].title |
Allows setting new value for properties (in this case title). |
[0].nested.foo |
Allows setting new value for property nested but will fail if not object type. |
user.contacts[0].phone |
Allows setting user contacts but only if array index 0 and only property phone. |
user.contacts[0].label |
Allows setting user contacts but only if array index 0 and only property label. |
user.contacts[*].label |
Allows setting property label to any index inside contacts array. |
bar.key1.b |
Allows to set "foo.key1.b" only. |
!bar.key1.b |
Denies to set "foo.key1.b" only. |
Expanded Example Scenario
Let's imagine a more complex JSON structure representing a user profile, including nested objects for personal details, permissions, and an array of contact methods.
from json_patch_rules import patch_rules
# Define a complex JSON object
data = {
"user": {
"name": "John Doe",
"email": "john@example.com",
"permissions": {
"edit": True,
"delete": False
},
"contacts": [
{"type": "home", "number": "1234567890", "label": "Home Phone"},
{"type": "work", "number": "0987654321", "label": "Work Phone"}
]
}
}
# Define rules to specify allowed updates
rules = [
"!user.permissions.delete", # Denies deletion of the delete permission under user permissions
"user.name", # Allows replacing the name attribute under user
"user.contacts[0].number", # Allows replacing the phone number in the first contact
"user.contacts[*].label", # Allows updating label for any contact in the contacts array
]
# Initialize patch rules
patch = patch_rules(rules)
# Define new data to apply
new_data = {
"user": {
"name": "Jane Doe",
"permissions": {
"edit": False,
"delete": True # This update will be denied by the rule
},
"contacts": [
{"number": "1111111111"}, # Allowed update
{"label": "Emergency Phone"} # Allowed update
]
}
}
# Apply the patch
result = patch.apply(data, new_data)
# Output the updated JSON object
print("Patched Data:", result.data) # patched data
print("Denied Paths:", result.denied_paths) # Denied Paths: ['user.permissions.edit', 'user.permissions.delete']
print("Successed Paths:", result.successed_paths) # Successed Paths: ['user.name', 'user.contacts[0].number', 'user.contacts[1].label']
Explaining the Code
Initializing the Json Patch Rules Library
- Importing the Library:
from json_patch_rules import patch_rules
This line imports thepatch_rules
function from the Json Patch Rules library, making it available to use in the script.
Defining the Data Structure
- JSON Data (
data
):data = { "user": { "name": "John Doe", "email": "john@example.com", "permissions": { "edit": True, "delete": False }, "contacts": [ {"type": "home", "number": "1234567890", "label": "Home Phone"}, {"type": "work", "number": "0987654321", "label": "Work Phone"} ] } }
This JSON object represents a structured user profile with personal details, permissions, and contacts. Each contact is detailed with a type, number, and label.
Setting Up the Rules
- Rules Definition (
rules
):rules = [ "!user.permissions.delete", "user.name", "user.contacts[0].number", "user.contacts[*].label", ]
Here, we define a list of strings where each string is a rule that governs how the JSON data can be updated:"!user.permissions.delete"
denies any changes to thedelete
permission."user.name"
allows changes to the user's name."user.contacts[0].number"
allows changes to the number of the first contact."user.contacts[*].label"
allows changes to the label of any contact in the contacts array.
Initializing Patch Rules
- Patch Initialization (
patch
):patch = patch_rules(rules)
This creates a new instance of patch rules using the defined rules. This instance will be used to apply changes to the JSON data according to the specified rules.
Defining New Data for Updates
- New Data (
new_data
):new_data = { "user": { "name": "Jane Doe", "permissions": { "edit": False, "delete": True }, "contacts": [ {"number": "1111111111"}, {"label": "Emergency Phone"} ] } }
Specifies the proposed changes, including updates to the user's name, permissions, and contact details. According to the rules, the change to thedelete
permission will be denied.
Applying the Patch
- Applying the Patch (
result
):result = patch.apply(data, new_data)
Theapply
method is called on thepatch
object with the original data and the new data. It processes each change against the established rules, applying allowed updates and blocking prohibited ones.
Result Analysis
- Output Results:
print("Patched Data:", result.data) print("Denied Paths:", result.denied_paths) print("Successed Paths:", result.successed_paths)
After applying the patch, this section prints the updated JSON data, paths of denied updates, and paths of successful updates. This feedback helps validate that the Json Patch Rules library is effectively controlling data modifications according to the defined rules.
The result
object will contain details about the operation, including which paths were updated successfully and which were denied.
Contributing
Contributions are welcome! Please feel free to submit pull requests, report bugs, and suggest features.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file python_json_patch_rules-0.3.2.tar.gz
.
File metadata
- Download URL: python_json_patch_rules-0.3.2.tar.gz
- Upload date:
- Size: 9.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e0f60b7916bcafe2e6c51c11f4afa13b848a54bc4878d6f9a016bb8e5033e818 |
|
MD5 | fbfcc0b9274ffdb75c53430f0988551b |
|
BLAKE2b-256 | 360227c6a40957d2dbc77a49d279d6b3561d67cb3c128b01976dd08a82401bcd |
File details
Details for the file python_json_patch_rules-0.3.2-py3-none-any.whl
.
File metadata
- Download URL: python_json_patch_rules-0.3.2-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4d828e12c1909fa8bb32354477d02ba7b8a80fa7432953434656802c7911ecb8 |
|
MD5 | 1c81b11ae22e0989953d1736882c4312 |
|
BLAKE2b-256 | aefdd2f9e5aea0ab0064d14c69394ba375feabde0c0494adb0b9429fcc6c09e7 |