Skip to main content
Version: v8.0.0

Working with Firestore

This guide will walk you through performing CRUD (Create, Read, Update, Delete) operations in Firestore using the @hyper-fetch/firebase-admin adapter. We'll cover the available methods and demonstrate how to use them with practical examples.

What you'll learn
  • How to set up the Hyper-fetch client for Firestore
  • How to use getDocs to retrieve a collection
  • How to use getDoc to fetch a single document
  • How to add a new document with addDoc
  • How to modify a document with setDoc and updateDoc
  • How to remove a document with deleteDoc

Setup

First, let's set up our Hyper-fetch client to work with Firestore. We'll need to initialize the Firebase Admin SDK and pass the Firestore instance to our adapter.

import { createClient } from "@hyper-fetch/core";
import { firebaseAdminAdapter } from "@hyper-fetch/firebase-admin";
import * as admin from "firebase-admin";

// 1. Initialize Firebase Admin
// Make sure to replace with your actual service account key and database URL
const serviceAccount = require("./path/to/your/serviceAccountKey.json");

admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your-project-id.firebaseio.com",
});

const db = admin.firestore();

// 2. Define the data structure for our examples
interface Tea {
name: string;
origin: string;
type: "Green" | "Black" | "Oolong" | "Herbal";
year: number;
amount: number;
__key?: string; // This will be automatically added by Hyper-fetch
}

// 3. Create a Hyper-fetch client
// We set a base endpoint of 'teas' which corresponds to a Firestore collection
const client = createClient({
url: "teas/",
}).setAdapter(() => firebaseAdminAdapter(db));

Available Methods

The Firestore adapter maps familiar Firestore SDK methods to Hyper-fetch requests. This allows you to interact with your database using a consistent, declarative syntax.

The available methods are:

  • getDocs
  • getDoc
  • setDoc
  • updateDoc
  • addDoc
  • deleteDoc
const request = client.createRequest<{ response Tea[] }>()({
endpoint: "",
method: "getDocs", // "addDoc" | "getDoc" | "getDocs" | "setDoc" | "updateDoc" | "deleteDoc"
});
Realtime Updates

Due to its nature, we've solved the realtime listening a bit differently, and thus - this method is not allowed in a standard adapter. For the onSnapshot-like usage, please check how to listen to queries.


Usage Examples

Let's walk through a complete CRUD cycle to see how these methods work together.

1. addDoc

To start, we'll add a new tea to our teas collection. The addDoc method creates a new document with an auto-generated ID.

const newData: Omit<Tea, "__key"> = {
name: "Pai Mu Tan",
origin: "China",
type: "Green",
year: 2023,
amount: 50,
};

const addDocReq = client.createRequest<{ response: Tea; payload: typeof newData }>()({
endpoint: "",
method: "addDoc",
});

const { data: addedTea, error: addError } = await addDocReq.setData(newData).send();

if (addedTea) {
console.log("Added tea:", addedTea);
// The response data includes the original data plus the new document ID in the `__key` field.
// { name: 'Pai Mu Tan', ..., __key: 'Abc123xyz' }
}

When using addDoc, the response data is the same as the data you sent, but with the addition of a __key field containing the newly created document's ID.

2. getDoc

Now, let's fetch the tea we just created using its ID. The :teaId in the endpoint is a dynamic parameter that we'll fill in using setParams.

const getDocReq = client.createRequest<{ response Tea }>()({
endpoint: ":teaId",
method: "getDoc",
});

// We use the `__key` from the previous step to fetch the document
const { data, extra } = await getDocReq.setParams({ teaId: addedTea.__key }).send();

console.log("Fetched tea:", data);

extra response

  • ref: The Firestore DocumentReference.
  • snapshot: The raw Firestore DocumentSnapshot.

3. getDocs

To fetch all the teas in our collection, we use getDocs. This method returns an array of documents.

const getDocsReq = client.createRequest<{ response Tea[] }>()({
endpoint: "",
method: "getDocs",
});

const { data: allTeas, extra: getDocsExtra } = await getDocsReq.send();

// data is an array of objects, where each object also contains the `__key` property.
console.log("All teas:", allTeas);

extra response

  • ref: The Firestore CollectionReference.
  • snapshot: The raw Firestore QuerySnapshot.

4. setDoc

The setDoc method allows you to overwrite a document. If the document doesn't exist, it will be created.

const updatedData = {
name: "Pai Mu Tan (Organic)",
origin: "China",
type: "Green",
year: 2024,
amount: 100,
};

const setDocReq = client.createRequest<Tea, typeof updatedData>()({
endpoint: ":teaId",
method: "setDoc",
// You can also pass { merge: true } to merge fields instead of overwriting
});

const { data: setResponse } = await setDocReq.setParams({ teaId: addedTea.__key }).setData(updatedData).send();

// The response from setDoc is the same data that was sent.
console.log("Set response:", setResponse);

5. updateDoc

If you only want to update specific fields in a document without overwriting the entire document, use updateDoc.

const partialUpdate = {
amount: 95,
year: 2025,
};

const updateDocReq = client.createRequest<Tea, typeof partialUpdate>()({
endpoint: ":teaId",
method: "updateDoc",
});

const { data: updateResponse } = await updateDocReq.setParams({ teaId: addedTea.__key }).setData(partialUpdate).send();

// The response from updateDoc is the same data that was sent for the update.
console.log("Update response:", updateResponse);

6. deleteDoc

Finally, let's remove the tea from our collection using deleteDoc.

const deleteDocReq = client.createRequest()({
endpoint: ":teaId",
method: "deleteDoc",
});

const { data: deleteResponse } = await deleteDocReq.setParams({ teaId: addedTea.__key }).send();

// The response from deleteDoc is always `null`.
console.log("Delete response:", deleteResponse);