Google Cloud Services - Firestore

This extension allows to inject a com.google.cloud.firestore.Firestore object inside your Quarkus application.

Be sure to have read the Google Cloud Services extension pack global documentation before this one, it contains general configuration and information.

Bootstrapping the project

First, we need a new project. Create a new project with the following command (replace the version placeholder with the correct one):

mvn io.quarkus:quarkus-maven-plugin:<quarkusVersion>:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=firestore-quickstart \
    -Dextensions="resteasy-reactive-jackson,quarkus-google-cloud-firestore"
cd firestore-quickstart

This command generates a Maven project, importing the Google Cloud Firestore extension.

If you already have your Quarkus project configured, you can add the quarkus-google-cloud-firestore extension to your project by running the following command in your project base directory:

./mvnw quarkus:add-extension -Dextensions="quarkus-google-cloud-firestore"

This will add the following to your pom.xml:

<dependency>
    <groupId>io.quarkiverse.googlecloudservices</groupId>
    <artifactId>quarkus-google-cloud-firestore</artifactId>
</dependency>

Some example

This is an example usage of the extension: we create a REST resource with a single endpoint that creates a 'persons' collection, inserts three persons in it, then search for persons with last name Doe and returns them.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutures;
import com.google.cloud.firestore.CollectionReference;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.Query;
import com.google.cloud.firestore.QuerySnapshot;
import com.google.cloud.firestore.WriteResult;

@Path("/firestore")
public class FirestoreResource {
    @Inject
    Firestore firestore; // Inject Firestore

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String firestore() throws ExecutionException, InterruptedException {
        // Insert 3 persons
        CollectionReference persons = firestore.collection("persons");
        List<ApiFuture<WriteResult>> futures = new ArrayList<>();
        futures.add(persons.document("1").set(new Person(1L, "John", "Doe")));
        futures.add(persons.document("2").set(new Person(2L, "Jane", "Doe")));
        futures.add(persons.document("3").set(new Person(3L, "Charles", "Baudelaire")));
        ApiFutures.allAsList(futures).get();

        // Search for lastname=Doe
        Query query = persons.whereEqualTo("lastname", "Doe");
        ApiFuture<QuerySnapshot> querySnapshot = query.get();
        return querySnapshot.get().getDocuments().stream()
                .map(document -> document.getId() + " - " + document.getString("firstname") + " "
                        + document.getString("lastname") + "\n")
                .collect(Collectors.joining());
    }
}
Here we let Firestore serialize the Person object, Firestore will use reflection for this. So if you deploy your application as a GraalVM native image you will need to register the Person class for reflection. This can be done by annotating it with @RegisterForReflection.

Dev Service

Configuring the Dev Service

The extension provides a Dev Service that can be used to run a local Firestore emulator. This is useful for testing purposes, so you don’t have to rely on a real Firestore instance. By default, the Dev Service is disabled, but you can enable it by setting the

  • quarkus.google.cloud.firestore.devservice.enabled property to true

You can also set the

  • quarkus.google.cloud.firestore.devservice.port property to change the port on which the emulator will be started (by default there is no port set, so the emulator will use a random port)

The emulator is started once and reused when the application restarts (for example in live reload, continuous testing, or between the test classes of a @QuarkusTest suite that use different test profiles). It is stopped when the application stops or when the Dev Service configuration changes.

In dev mode, the emulator is also shared between applications by default: if an emulator started by another Quarkus application is running, it will be used instead of starting a new one. You can control this with the

  • quarkus.google.cloud.firestore.devservice.shared property (defaults to true)

  • quarkus.google.cloud.firestore.devservice.service-name property (defaults to firestore), the value of the quarkus-dev-service-google-cloud-firestore label used to find the shared emulator

Using the Dev Service

Once the Dev Service is enabled, the Firestore client which you can @Inject in your application will be configured to use the emulator.

Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

Indicates to use the dev service for Firebase. The default value is not setup unless the firebase module is included. In that case, the Firebase devservices will by default be preferred and the DevService for PubSub will be disabled.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIREBASE_DEVSERVICE_PREFER_FIREBASE_DEV_SERVICES

boolean

Indicates whether the Firestore service should be enabled or not. The default value is 'false'.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_DEVSERVICE_ENABLED

boolean

false

Sets the Docker image name for the Google Cloud SDK. This image is used to emulate the Firestore service in the development environment. The default value is 'gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators'.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_DEVSERVICE_IMAGE_NAME

string

gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators

Specifies the emulatorPort on which the Firestore service should run in the development environment.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_DEVSERVICE_EMULATOR_PORT

int

Indicates if the Firestore emulator managed by Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services starts a new container.

The discovery uses the quarkus-dev-service-google-cloud-firestore label. The value is configured using the service-name property.

Container sharing is only used in dev mode.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_DEVSERVICE_SHARED

boolean

true

The value of the quarkus-dev-service-google-cloud-firestore label attached to the started container. This property is used when shared is set to true. In this case, before starting a container, Dev Services looks for a container with the quarkus-dev-service-google-cloud-firestore label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise, it starts a new container with the quarkus-dev-service-google-cloud-firestore label set to the specified value.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_DEVSERVICE_SERVICE_NAME

string

firestore

Overrides the default service host. This is most commonly used for development or testing activities with a local Google Cloud Firestore emulator instance.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_HOST_OVERRIDE

string

Forces the usage of emulator credentials. The logic automatically uses emulator credentials in case the host running the library uses "localhost". This behaviour can be overridden by specifying this configuration property:

  • If true: force usage of emulator credentials

  • If false: force not using emulator credentials If not present: keep the automatic behaviour

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_USE_EMULATOR_CREDENTIALS

boolean

Total timeout for all retries.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_TOTAL_TIMEOUT

Duration 

Delay before the first retry.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_INITIAL_RETRY_DELAY

Duration 

Controls the rate of change of the delay. Next retry is multiplied by this factor.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_RETRY_DELAY_MULTIPLIER

double

Limits the maximum retry delay.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_MAX_RETRY_DELAY

Duration 

Determines the maximum number of attempts. When number of attempts reach this limit they stop retrying.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_MAX_ATTEMPTS

int

Timeout for the initial RPC.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_INITIAL_RPC_TIMEOUT

Duration 

Controls the rate of change of the RPC timeout. Next timeout is multiplied by this factor.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_RPC_TIMEOUT_MULTIPLIER

double

Limits the maximum RPC timeout.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_RETRY_MAX_RPC_TIMEOUT

Duration 

The firestore database identifier. It not set, the default will be used.

Environment variable: QUARKUS_GOOGLE_CLOUD_FIRESTORE_DATABASE_ID

string

About the Duration format

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

You can also use a simplified format, starting with a number:

  • If the value is only a number, it represents time in seconds.

  • If the value is a number followed by ms, it represents time in milliseconds.

In other cases, the simplified format is translated to the java.time.Duration format for parsing:

  • If the value is a number followed by h, m, or s, it is prefixed with PT.

  • If the value is a number followed by d, it is prefixed with P.