SkillByAIOpen interactive version →

Lesson 17 / 25

Cloud Functions and the Admin SDK

HTTP, callable and Firestore triggers.

Three common trigger types

Cloud Functions for Firebase run Node.js (or Python) code on Google infrastructure; the second-generation API is imported from paths such as firebase-functions/v2/https. HTTP functions (onRequest) handle webhooks and plain HTTP. Callable functions (onCall) are called from the client SDK with httpsCallable; Firebase passes the caller's auth (and App Check) context automatically, and you signal errors with HttpsError. Event triggers such as onDocumentCreated react to Firestore, Auth or Storage changes. Inside functions, the Admin SDK has full access and bypasses Security Rules, so validate input and check request.auth yourself. Deploying functions requires the pay-as-you-go plan; check the docs for current plan requirements.

Callable and trigger functions

TypeScript in functions/src/index.ts.

import { onCall, HttpsError } from "firebase-functions/v2/https";
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { initializeApp } from "firebase-admin/app";
import { getFirestore, FieldValue } from "firebase-admin/firestore";

initializeApp();
const db = getFirestore();

// called from the client: httpsCallable(getFunctions(app), "joinTeam")({ teamId })
export const joinTeam = onCall(async (request) => {
  if (!request.auth) throw new HttpsError("unauthenticated", "Sign in first.");
  const teamId = request.data?.teamId;
  if (typeof teamId !== "string") throw new HttpsError("invalid-argument", "teamId required.");
  await db.doc(`teams/${teamId}/members/${request.auth.uid}`).set({
    joinedAt: FieldValue.serverTimestamp(),
  });
  return { ok: true };
});

// keep a denormalised counter up to date
export const onCommentCreated = onDocumentCreated("posts/{postId}/comments/{commentId}", async (event) => {
  await db.doc(`posts/${event.params.postId}`).update({
    commentCount: FieldValue.increment(1),
  });
});

Make triggers idempotent

Event triggers are delivered at least once, so a function may run more than once for the same event. Design writes so a repeat run does no harm, or record processed event ids.

Quick check: Why must a callable function check request.auth and validate data itself?

  • Rules run after the function
  • Callable functions cannot read auth
  • The Admin SDK bypasses Security Rules, so the function is the only guard
  • HttpsError disables validation
Answer

The Admin SDK bypasses Security Rules, so the function is the only guard — Trusted code carries the responsibility.