firebase-admin-node icon indicating copy to clipboard operation
firebase-admin-node copied to clipboard

[Firestore] Can not connect to both production and local emulator database

Open danielo515 opened this issue 1 year ago • 2 comments

[REQUIRED] Step 1

Yes, I think this is the right place

[REQUIRED] Step 2: Describe your environment

  • Operating System version: MacOS
  • Firebase SDK version: 11.0.0
  • Firebase Product: Firestore
  • Node.js version: 16
  • NPM version: yarn

[REQUIRED] Step 3: Describe the problem

Steps to reproduce:

Please take a look at the attached code in the next section. When you try to run that code you will get an error saying that TypeError: this.ensureApp(...).firestore is not a function. Seems that the initializeApp method is not returning an actual app instance that includes everything.

I want to be able to connect both to my production app and to my local emulator suite so I can do some dumps from one to the other.

admin.firestore.setLogFunction(console.log);

This will print Firestore logs to the console.

Relevant Code:

import { cert, initializeApp, applicationDefault } from 'firebase-admin/app';
import * as admin from 'firebase-admin';
import authData from '../admin-sdk.json';
import { Firestore } from 'firebase-admin/firestore';
import { emulators } from '../firebase.json';

initializeApp({
  // the cert accepts either an string or an object, but it si wrongly typed
  credential: cert(authData as unknown as string),
});

const localApp = initializeApp(
  { credential: applicationDefault(), databaseURL: `localhost:${emulators.firestore.port}` },
  'local',
);

export const db = admin.firestore();
export const localDb = admin.firestore(localApp);

danielo515 avatar Jul 27 '22 11:07 danielo515

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.

google-oss-bot avatar Jul 27 '22 11:07 google-oss-bot

So it seems that THE ONLY WAY to connect to a local firestore database is by setting the environment variable. I tried this and, indeed it connected to the local database, what I can not be sure about is I am able to connect to both at the same time. It will be nice if docs were more clear about this, and it will be awesome if you allow to just pass that as a configuration option in the initialize app config object

danielo515 avatar Jul 27 '22 11:07 danielo515

You can probably set the emulator environment variable in the code and remove once you initialize the production app. Something like below:


process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080';

const localApp = initializeApp(
  { projectId: 'test-project', databaseURL: `localhost:${emulators.firestore.port}` },
  'local',
);

delete process.env.FIRESTORE_EMULATOR_HOST;

In the future, please use StackOverflow for usage questions.

lahirumaramba avatar Jan 17 '23 20:01 lahirumaramba

I'm trying to do this as well, and I think it's a perfectly reasonable feature request to not have to depend on env vars to accomplish this. It's just not very clean to have to add and remove env vars on a temporary basis when an API would be better. There should be some options to pass to initializeApp() to ask it to use the emulator, or alternatively, an API similar to those provided by the client SDKs to tell the app to connect to an emulator.

CodingDoug avatar Oct 03 '23 18:10 CodingDoug

Hi @CodingDoug ,

Thank you for suggesting this. There are different products in Firebase and you get the choices to use some of it against emulator and others against production. So it is not easy to add simple options on this top level function initializeApp.

However, you can do something like the following to bypass environment variables:

const admin = require('firebase-admin');
admin.initializeApp();

const firestore = admin.firestore();

firestore.settings({ 
  ...firestore.settings,
  host: 'localhost:8080',
  ssl: false
}); 

cherylEnkidu avatar Oct 05 '23 18:10 cherylEnkidu

@cherylEnkidu Wouldn't it be possible to introduce a new function to initialize the app against the emulator alone? I don't really need to single out one product for use with the emulator. What I want is two initialized apps, one against the project and another against the emulator, so that I can have an easier time copying data between them using more than one product.

Right now I'm doing this:

import { initializeApp } from "firebase-admin/app"
import { getAuth } from "firebase-admin/auth"
import { getFirestore } from "firebase-admin/firestore"

export const remote = initializeApp()
export const remoteAuth = getAuth(remote)
export const remoteFirestore = getFirestore(remote)

process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080'
export const local = initializeApp(undefined, "local")
export const localAuth = getFirestore(local)
export const localFirestore = getFirestore(local)
delete process.env.FIRESTORE_EMULATOR_HOST

It seems unnecessarily complex when I could instead just use a different initializer function for the emulator-only instance.

CodingDoug avatar Oct 05 '23 21:10 CodingDoug

Hi @CodingDoug ,

Can you open a new issue, label api:core, and also provide a expected code sample? Developers from the core team will collaborate with you. Thank you.

cherylEnkidu avatar Oct 06 '23 16:10 cherylEnkidu

@cherylEnkidu Added here: https://github.com/firebase/firebase-admin-node/issues/2327 I'm unable to manipulate labels here.

CodingDoug avatar Oct 06 '23 19:10 CodingDoug