Use Cases

Claude Code × GCP Cloud Functions Guia Completo | Desenvolvimento Serverless Ultra-Rápido

Otimize o GCP Cloud Functions com Claude Code. Implemente triggers HTTP/Pub/Sub/Firestore, testes locais e automação de implantações com exemplos de código reais da experiência de Masa.

Cloud Run Era Demais — Por Isso Escolhi Cloud Functions

Sou Masa, desenvolvedor por trás do claudecode-lab.com.

Quando comecei a usar GCP Serverless, considerei o Cloud Run. Flexível e baseado em containers — mas para tarefas como “apenas receber um único webhook” ou “executar um batch uma vez à noite”, era claramente exagerado. É por isso que mudei para Cloud Functions Gen2.

Com Claude Code, mais de 90% do meu código Cloud Functions é gerado automaticamente.


Passo 1: Função com Trigger HTTP

import { http, HttpFunction } from "@google-cloud/functions-framework";
import { Request, Response } from "express";
import { Firestore } from "@google-cloud/firestore";

const db = new Firestore();
const VALID_TOKEN = process.env.API_SECRET_TOKEN;

interface ActionRequest {
  userId: string;
  action: string;
}

const handleAction: HttpFunction = async (req: Request, res: Response) => {
  // Configurar headers CORS
  res.set("Access-Control-Allow-Origin", "*");
  if (req.method === "OPTIONS") {
    res.set("Access-Control-Allow-Methods", "POST");
    res.set("Access-Control-Allow-Headers", "Authorization, Content-Type");
    res.status(204).send("");
    return;
  }

  // Permitir apenas POST
  if (req.method !== "POST") {
    res.status(405).json({ success: false, message: "Método Não Permitido" });
    return;
  }

  // Validar Bearer token
  const authHeader = req.headers.authorization ?? "";
  if (!authHeader.startsWith("Bearer ") || authHeader.slice(7) !== VALID_TOKEN) {
    res.status(401).json({ success: false, message: "Não Autorizado" });
    return;
  }

  const body = req.body as Partial<ActionRequest>;
  if (!body.userId || !body.action) {
    res.status(400).json({ success: false, message: "userId e action são obrigatórios" });
    return;
  }

  try {
    const logRef = await db.collection("action_logs").add({
      userId: body.userId,
      action: body.action,
      timestamp: new Date(),
      ip: req.ip,
    });
    res.status(200).json({ success: true, message: "Ação registrada", logId: logRef.id });
  } catch (err) {
    console.error("Erro ao escrever no Firestore:", err);
    res.status(500).json({ success: false, message: "Erro Interno do Servidor" });
  }
};

http("handleAction", handleAction);

Passo 2: Função com Trigger Pub/Sub

import { cloudEvent, CloudEvent } from "@google-cloud/functions-framework";
import { MessagePublishedData } from "@google/events/cloud/pubsub/v1/MessagePublishedData";
import { Storage } from "@google-cloud/storage";

const storage = new Storage();

interface ImageUploadedMessage {
  bucketName: string;
  filePath: string;
}

cloudEvent<MessagePublishedData>("handleImageUploaded", async (event: CloudEvent<MessagePublishedData>) => {
  const base64Data = event.data?.message?.data;
  if (!base64Data) {
    console.warn("Nenhum dado de mensagem recebido, ignorando");
    return;
  }

  const rawJson = Buffer.from(base64Data, "base64").toString("utf-8");
  let payload: ImageUploadedMessage;
  try {
    payload = JSON.parse(rawJson) as ImageUploadedMessage;
  } catch {
    console.error("JSON inválido na mensagem Pub/Sub:", rawJson);
    return;
  }

  const { bucketName, filePath } = payload;
  try {
    const [metadata] = await storage.bucket(bucketName).file(filePath).getMetadata();
    console.log("Metadados do arquivo:", { nome: metadata.name, tamanho: metadata.size });
  } catch (err) {
    // Lançar exceção faz o Pub/Sub tentar novamente a mensagem
    console.error(`Falha ao processar ${filePath}:`, err);
    throw err;
  }
});

Passo 3: Testes Locais e Implantação

# Iniciar localmente
npm run build
npx @google-cloud/functions-framework --target=handleAction --port=8080

# Enviar requisição de teste
curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer token-de-teste" \
  -d '{"userId": "user-123", "action": "login"}'

# Implantar no GCP
gcloud functions deploy handleAction \
  --gen2 \
  --runtime=nodejs22 \
  --region=southamerica-east1 \
  --source=. \
  --entry-point=handleAction \
  --trigger-http \
  --allow-unauthenticated \
  --memory=512Mi \
  --timeout=60s \
  --set-secrets="API_SECRET_TOKEN=api-secret-token:latest"

4 Armadilhas Comuns

ArmadilhaProblemaSolução
Cold StartLatência de 2–5 s com instâncias inativas--min-instances=1 para funções críticas
Limite de TimeoutMáximo 9 minutos (540 s)Dividir tarefas longas via Pub/Sub
Permissões Secret ManagerPermission denied em tempo de execuçãoConceder papel secretmanager.secretAccessor
Falta de MemóriaOOM em processamento pesadoConfigurar --memory=2Gi --cpu=2

Resumo

TriggerCaso de UsoConsideração Principal
HTTPWebhooks, endpoints de APIAutenticação, CORS
Pub/SubProcessamento assíncrono de eventosDecodificação base64, design de retry
FirestoreReagir a mudanças de dadosEvitar loops infinitos
Cloud SchedulerBatch jobs agendadosValidação OIDC, fuso horário

Artigos Relacionados

#claude-code #gcp #cloud-functions #typescript #serverless #pubsub
Grátis

PDF gratuito: Cheatsheet do Claude Code em 5 minutos

Basta informar seu e-mail e enviamos na hora o cheatsheet em uma página A4.

Cuidamos dos seus dados pessoais e nunca enviamos spam.

Leve seu fluxo no Claude Code a outro nível

50 modelos de prompt testados em campo, prontos para colar direto no Claude Code.

Masa

Sobre o autor

Masa

Engenheiro apaixonado por Claude Code. Mantém o claudecode-lab.com, uma mídia tech em 10 idiomas com mais de 2.000 páginas.