-   Notifications  
You must be signed in to change notification settings  - Fork 217
 
Description
If you've got a Firebase RTDB path component that starts with refs you won't be able to use .ref of the provided DataSnapshot that's passed into the function.
Bit of a fun one this is...
Related issues
[REQUIRED] Version info
node: 14.17.4
 firebase-functions: 3.18.1
 firebase-tools: 10.1.0
 firebase-admin: 10.0.2
[REQUIRED] Test case
Deploy the below function:
const functions = require('firebase-functions') exports.pathUnableToUseRef = functions.database.ref('childStartsWithRef/{id}').onWrite(async (change, context) => { functions.logger.debug(`Change at on child of childStartsWithRef: change.after.key='${change.after.key  }', context.params.id='${context.params.id}'`, { context }) functions.logger.debug(`change.after.ref.toString(): ${change.after.ref.toString()}`) })[REQUIRED] Steps to reproduce
Deploy the above function and then run:
firebase database:set "/childStartsWithRef/ref" --data '"foobar"'
After checking the function logs, you can see this executes the function successfully:
Function execution started Change at on child of childStartsWithRef: change.after.key='ref', context.params.id='ref' change.after.ref.toString(): https://my-project.firebaseio.com/childStartsWithRef/ref Function execution took 6 ms, finished with status: 'ok' However, when running:
 firebase database:set "/childStartsWithRef/refs" --data '"foobar"'
This causes the function execution to fail.
[REQUIRED] Expected behavior
For the .ref access to work and the following to be outputted on the second execution:
Function execution started Change at on child of childStartsWithRef: change.after.key='refs', context.params.id='refs' change.after.ref.toString(): https://my-project.firebaseio.com/childStartsWithRef/refs Function execution took 6 ms, finished with status: 'ok' [REQUIRED] Actual behavior
Second execution of function fails:
Function execution started Change at on child of childStartsWithRef: change.after.key='null', context.params.id='refs' [2022-03-09T15:03:33.858Z] @firebase/database: FIREBASE FATAL ERROR: Cannot parse Firebase url. Please use https://<YOUR FIREBASE>.firebaseio.com Function execution took 93 ms, finished with status: 'error' Note also that the .key of the DataSnapshot is null.
Were you able to successfully deploy your functions?
Yes.
Extra info
Pretty sure its because of the regex to extract the instance and path from the resource:
 
firebase-functions/src/providers/database.ts
Line 323 in f45e45f
| const resourceRegex = `projects/([^/]+)/instances/([a-zA-Z0-9\-^/]+)/refs(/.+)?`; | 
const resource = 'projects/_/instances/my-database/refs/childStartsWithRef/refs' const resourceRegex = `projects/([^/]+)/instances/([a-zA-Z0-9\-^/]+)/refs(/.+)?`; const match = resource.match(new RegExp(resourceRegex)); console.log(match)Outputs:
[ 'projects/_/instances/my-database/refs/childStartsWithRef/refs', '_', 'my-database/refs/childStartsWithRef', undefined, index: 0, input: 'projects/_/instances/my-database/refs/childStartsWithRef/refs', groups: undefined ] But changing the instance path component regex to being non-greedy (([a-zA-Z0-9\-^/]+?)) does fix things - I'm not saying this is the best fix, but certainly fixes the example case:
const resource = 'projects/_/instances/my-database/refs/childStartsWithRef/refs' const resourceRegex = `projects/([^/]+)/instances/([a-zA-Z0-9\-^/]+?)/refs(/.+)?`; const match = resource.match(new RegExp(resourceRegex)); console.log(match)Outputs:
[ 'projects/_/instances/my-database/refs/childStartsWithRef/refs', '_', 'my-database', '/childStartsWithRef/refs', index: 0, input: 'projects/_/instances/my-database/refs/childStartsWithRef/refs', groups: undefined ]