Firestore REST API, POST request succeeds, document does not appear in emulator UI, and cloud triggers do not fire

Viewed 83

I have been experiencing an ongoing issue with Firestore since last week.

Issue: writes are not being made to Firestore database from the REST API.

  • This behaviour has been observed in the emulator, and in production.
  • The issue does not appear when running unit tests with the emulator, writes occur as expected and the database is exported successfully.
  • When running the emulator.
    • GET requests via the REST API will return with success, and the expected document is returned.
    • POST requests via the REST API (createDocument) will return with success, and the expected document is returned, however the document will not appear in the emulator UI.
    • In response to createDocument at this path, the Firestore Cloud Trigger does not fire, which would delete the document after it has been created.
    • If the same POST request is made again, it will fail with code 409, and the message: "entity already exists: <path_to_document>". But again, its not showing up in emulator UI.
    • On exit, the database exported by the emulator will not include the document from the POST request.
    • Restarting the emulator will allow the POST request to be made successfully, but as above the document does not appear in the emulator UI, cloud triggers don't fire, and subsequent requests also fail.
  • I first observed the issue after attempting to deploy to production, but received an error (can't remember the error and I didn't save the log, sorry!). I assumed the issue was due to out of date node packages, so I updated firebase-tools and node packages, but the issue persisted.
  • Writes had been working as expected for months, this issue is recent.

POST example:

curl --request POST \
  'http://127.0.0.1:8080/v1/projects/demo-<PROJECT_ID>/databases/(default)/documents/HOME?documentId=11223344&key=<API_KEY>' \
  --header 'Authorization: Bearer <TOKEN>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{ "fields":{ "my_field":{ "stringValue":"random" }} }' \
  --compressed

**Note: PROJECT_ID, API_KEY and TOKEN had correct values, I just removed them for this post.

  • I recreated the behaviour in a fresh standalone firebase project with minimal code.
  • Setting Firestore rules to allow all reads and writes, still produces the same behaviour.
  • I have tried using older versions of firebase-tools, and node packages, without success.
  • I also removed and reinstalled the most recent version of Java (v18).

Firestore rules and index.js below Any help would be greatly appreciated!

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true
    }
  }
}
const functions = require( "firebase-functions" );
exports.userPath = functions
  .firestore.document( "{root}/{node}" )
  .onCreate( async( snap, context ) => {
    try
    {
      console.log( "Document @ path: "+snap.ref.path );
        await sleep( 250 );
        await snap.ref.delete();
      return console.log( "Document deleted @ path: "+snap.ref.path );
    }
    catch( error )
        { return await console.log( "FATAL error" ); }
});
1 Answers

The Cloud Firestore Emulator attempts to faithfully replicate the behavior of the production service with some notable limitations like on transaction for example,when you're testing features that involve multiple concurrent writes to one document, the emulator may be slow to complete write requests in some cases, locks may take up to 30 seconds to be released. It is recommended to consider adjusting test timeouts accordingly, if needed.

In a typical lifecycle, a Cloud Firestore function does the following:

  1. Waits for changes to a particular document.
  2. Triggers when an event occurs and performs its tasks .
  3. Receives a data object that contains a snapshot of the data stored in the specified document. For onWrite or onUpdate events, the data object contains two snapshots that represent the data state before and after the triggering event.

You may want to check and confirm that the document paths must not contain trailing slashes.
The code you shared uses the onCreate method,which responds only to document creations.For a DocumentSnapshot that points to a non-existing document, any data access will return 'undefined'. You can use the exists property to explicitly verify a document's existence.
A delete for a non-existing document is treated as a success (unless lastUptimeTime is provided).

        (snapshot: QueryDocumentSnapshot, context: EventContext) => any)
       : CloudFunction<QueryDocumentSnapshot>

Please check the helpful documentation for more information on the emulators which enable testing of cross product interactions and Firestore DocumentSnapshot usages.

Related