Introduction
Recently we needed to synchronize a value from a Firestore document with a key in Remote Config. The value in Firestore is written to as part of a deploy pipeline we do not have control of. Rather than copying this value by hand each time it changes, it is preferable to synchronize the value automatically.
To do this I used a Cloud Function and the built-in trigger support for Firestore.
Firestore triggers
The firebase_functions library has built-in support for Firestore triggers. By adding the on_document_updated decorator to our function, it will run each time there is a change in the document in Firestore.
Using the database, document, and region parameters we can focus the trigger on a specific document:
from firebase_functions import firestore_fn
@firestore_fn.on_document_updated(
database="db-name",
document="doc/path",
region="europe-west4"):
def sync_value_to_remote_config(event):
...
For the region value, I picked the same region where the database resides.
Getting the data from Firestore
The old data and the new data can be access via the DocumentSnapshot event:
old_data = event.data.before.to_dict()
changed_data = event.data.after.to_dict()
In this case I need the token value from the document. I can get it using the changed_data dict:
token = changed_data.get("token")
Getting the data into Remote Config
At this juncture I had entered unchartered territory. I decided to see if Claude could help me shortcut the process by providing code that would show me how to insert a value into Remote Config.
This did not go well. It suggested APIs that didn’t exists in the Firebase Admin SDK and I was in a cycle of “This didn’t work, I got this output” → “Try this instead …”.
Using the power of old-school searching I found out that Remote Config has a REST API.
GET data from Remote Config
The GET https://firebaseremoteconfig.googleapis.com/v1/projects/{project_id}/remoteConfig operation returns the Remote Config data for the project.
response = requests.get(url, headers=headers)
template = response.json()
This data can then be updated for the specific parameter we are interested in, in this case token:
# Build the parameter with conditional values
parameter = {
"defaultValue": {"value": default_value},
"description": description,
}
# Add conditional values if any exist with token read from Firestore
parameter["conditionalValues"] = {}
parameter["conditionalValues"]["cond_ios"] = {"value": token}
parameter["conditionalValues"]["cond_android"] = {"value": token}
# And now update the parameter in the remote config data
template["parameters"]["token"] = parameter
PUT data into Remote Config
The Remote Config data is now changed locally, and we can use PUT https://firebaseremoteconfig.googleapis.com/v1/projects/{project_id}/remoteConfig to update the data remotely:
requests.put(url, data=json.dumps(template))
Deploying the function
The firebase admin CLI can be used to deploy the function, using the name of the Python function as the name of the cloud function:
firebase deploy \
--only functions:sync_value_to_remote_config \
--project <project_id>
Further reading
The source code for a real-world example is available in the sync-firestore-to-remote-config repo on Bitbucket.