My team has discussed this lately, and can't seem to determine for sure actual/intended behavior:
If you have a security rule like the following:
match /categories/{document=**} {
allow update: if request.auth.uid != null
&& request.resource.data.firstName is string
&& request.resource.data.lastName is string;
}
And you create an update statement from the frontend to /categories/ with the following data:
{
firstName: 'A valid firstName'
}
Is the security rule then supposed to pass or fail?
In the reference documentation, it says that
Developer provided data is surfaced in request.resource.data, which is a map containing the fields and values. Fields not provided in the request which exist in the resource are added to request.resource.data
Related questions:
- Does this mean that the success/fail depends on the existing data in the node?
- What happens if someone tries to update with data not
specified in the security rule, i.e.
{age: 28}
- What is the recommended way to validate update data?
Question 3 with more details (schema question) Suppose you have a model like this:
interface Category {
firstName: string;
lastName: string;
age?: int;
groupId?: string;
}
Now we create a security rule like this:
match /categories/{document=**} {
allow update: if request.auth.uid != null
&& request.resource.data.firstName is string
&& request.resource.data.lastName is string;
&& request.resource.data.age is int;
&& request.resource.data.groupId is string;
}
Then we have the following scenario, as I understand:
None of those scenarios fits well with optional properties. Because if you have to provide all properties (like in scenario 1) it is not really optional properties. And if you don't provide them, like in scenario 2, it fails.
Maybe I am missing something here, a basic guide on how to validate data with optional properties being written to firestore?
A security rule for an optional parameter, something like this:
match /categories/{document=**} {
allow update: if request.auth.uid != null
&& request.resource.data.firstName is string
&& request.resource.data.lastName is string;
&& request.resource.data.age is int; // ignore if NOT provided
&& request.resource.data.groupId is string; // ignore if NOT provided
}
That update will succeed if the document being updated already has a
lastName
field and this field is astring
. (I'm assuming you're running this update while authenticated so thatrequest.auth.uid != null
returns true)Answering the Related questions:
firstName
andlastName
set, adding theage
field will succeed. Note that the rule only checks if these 2 values are strings. It doesn't specify that the document can't have more than 2 fields.Update:
What I understood from your updated question 3 is that you want to only update the document if the user provided both first and last names. The age and groupId are optional.
To do that, you can check if this
request.resource.data.firstName
is not the one already on the database using:resource.data.firstName != request.resource.data.firstName
. So your security rules would look like this:Now with these rules, an update with this data will fail:
While these 3 will succeed:
Update 2: To have
age
andgroupId
as optional fields, use the OR operator and thehasAll()
function to check if the request has these fields: