跳到正文
cccskills
免费在 GitHub 公开

frontend-api-integration

Integrate with the FastAPI backend through the typed wrapper in frontend/lib/api.ts, attach Supabase JWTs for admin calls, and handle errors via ApiError. Use when adding/modifying API calls or wiring auth.

中文简介正在准备中。当前显示原文说明。

集成工具Supabase
查看安装方法

包含的文件(1)

  • SKILL.md6.7 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

API Integration Skill

Version: 1.0 | Working Directory: frontend/

API integration patterns for $ARGUMENTS in the Next.js frontend.

Overview

Single API surface, single auth flow:

  • frontend/lib/api.ts — typed fetch wrapper, ApiError class, helpers per endpoint
  • process.env.NEXT_PUBLIC_API_URL — base URL (no other URLs hardcoded anywhere)
  • Supabase Auth — admin JWT obtained from the Supabase session and passed as token to admin* helpers
  • @supabase/ssr — createSupabaseServerClient() for RSC/route handlers, createSupabaseBrowserClient() for Client Components

Constitution (Non-Negotiable Rules)

#RuleWhy
1Every backend call is a typed helper in lib/api.ts — never fetch against NEXT_PUBLIC_API_URL from a component or pageOne typed surface, one place to add headers/cache
2Admin calls require token — get it from supabase.auth.getSession() and pass to the helperBackend's require_admin checks the JWT
3Never hardcode the API URL — always via NEXT_PUBLIC_API_URLEnvironment-portable
4Throw ApiError — non-2xx responses already throw; let it propagate or catch with instanceof ApiError for detailConsistent error surface
5Strict types for request and response — define them in lib/types.ts, import where usedNo any
6No service-role secret on the frontend — never reference SUPABASE_SERVICE_ROLE_KEY from frontend/; that key is backend-onlyService-role bypasses RLS
7Cache choice is deliberate — admin/checkout helpers use cache: "no-store" (already set); use next: { revalidate: N } for ISR-eligible readsAvoid stale dashboards and accidental caching of mutations
8Multipart goes through a dedicated helper — adminUploadImage builds FormData and skips Content-Type so the browser sets the boundaryMultipart needs no manual Content-Type

When to Use

  • Adding a new FastAPI endpoint to consume from the UI
  • Modifying error handling for a call
  • Wiring admin auth into a new admin page
  • Adding a multipart upload

Quick Start

1. Add a typed helper

// frontend/lib/api.ts
export function adminBulkUpdateProducts(token: string, ids: string[], patch: Partial<Product>) {
  return api<Product[]>(`/api/admin/products/bulk`, {
    method: "POST",
    token,
    body: JSON.stringify({ ids, patch }),
  });
}

(If new shapes are involved, define them in frontend/lib/types.ts first.)

2. Use it from a Server Component (admin)

import { createSupabaseServerClient } from "@/lib/supabase/server";
import { adminListOrders } from "@/lib/api";

export default async function OrdersPage() {
  const supabase = await createSupabaseServerClient();
  const { data: { session } } = await supabase.auth.getSession();
  if (!session) redirect("/admin/login");
  const { items } = await adminListOrders(session.access_token, { limit: 50 });
  return <OrdersTable items={items} />;
}

3. Use it from a Client Component (admin mutation)

"use client";
import { useRouter } from "next/navigation";
import { createSupabaseBrowserClient } from "@/lib/supabase/client";
import { adminSetOrderStatus, ApiError } from "@/lib/api";

export function StatusDropdown({ orderId, current }: { orderId: string; current: string }) {
  const router = useRouter();
  async function onChange(next: string) {
    const supabase = createSupabaseBrowserClient();
    const { data: { session } } = await supabase.auth.getSession();
    if (!session) return;
    try {
      await adminSetOrderStatus(session.access_token, orderId, next);
      router.refresh();
    } catch (err) {
      alert(err instanceof ApiError ? String(err.detail) : "Update failed");
    }
  }
  return <select defaultValue={current} onChange={(e) => onChange(e.target.value)}>{/* ... */}</select>;
}

4. Public/storefront call from a Server Component

import { listProducts } from "@/lib/api";
const { items } = await listProducts({ q, limit: 24 });

Auth & Token Lifecycle

  • Sign-in / sign-out — frontend/app/admin/login/page.tsx uses createSupabaseBrowserClient() to call signInWithPassword / signOut
  • Session refresh — frontend/middleware.ts runs updateSession() for /admin/:path*, which keeps cookies fresh on every request
  • Reading the session — server: createSupabaseServerClient().auth.getSession(); client: createSupabaseBrowserClient().auth.getSession()
  • Role check — user.app_metadata?.role === "admin"; non-admins get a redirect/403 server-side
  • Never copy the access token into localStorage or attach it to non-admin requests

Cache Strategy

CallCache
Admin list/detailcache: "no-store" (already set) — admins want fresh data
Mutations (POST/PATCH)cache: "no-store"
Public product list/detailcache: "no-store" for now; switch to next: { revalidate: 60 } if traffic warrants
After a mutationrouter.refresh() from the Client Component to re-render server data

Errors

api() throws ApiError(status, detail) for non-2xx. detail is the parsed JSON body when the server returned JSON (FastAPI usually returns { "detail": "..." }), otherwise the raw text.

try { await checkout(payload); }
catch (e) {
  if (e instanceof ApiError) {
    const msg = typeof e.detail === "object" && e.detail && "detail" in e.detail
      ? String((e.detail as { detail: unknown }).detail)
      : String(e.detail);
    setError(msg);
  } else {
    setError("Network error");
  }
}

In Server Components: let it bubble to the closest error.tsx, or catch and notFound() for 404s (see exemplar app/(store)/products/[slug]/page.tsx).

Multipart Uploads

adminUploadImage is the template:

  • Build FormData, append the file
  • Bypass the JSON api() wrapper (it sets Content-Type: application/json)
  • Set Authorization manually; let the browser set the multipart boundary
  • Throw ApiError on non-2xx for parity

Don't add a generic multipart helper unless a second upload endpoint shows up.

Exemplar Files

  • frontend/lib/api.ts — every helper, ApiError, the api<T>() core
  • frontend/lib/supabase/server.ts — RSC/route-handler client
  • frontend/lib/supabase/client.ts — browser client
  • frontend/lib/supabase/middleware.ts — session refresh used by frontend/middleware.ts
  • frontend/lib/types.ts — request/response types

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Supabase Postgres + Storage + Auth operations from FastAPI — service-role client, RLS-aware queries, additive SQL migrations under backend/db/migrations, the create_order RPC, and the product-images bucket. Use when adding tables/columns, writing queries, calling RPCs, or working with Storage.

中文简介正在准备中。当前显示原文说明。

shanraisshan/learning-x-claude22026年5月7日 更新

Build FastAPI endpoints in the layered router → service → Supabase pattern, with Pydantic v2 schemas, JWT/admin gating, and consistent HTTPException-based domain errors. Use when adding/modifying any endpoint under backend/.

中文简介正在准备中。当前显示原文说明。

shanraisshan/learning-x-claude22026年5月7日 更新

pytest + httpx + TestClient patterns for the FastAPI backend. Dependency overrides for auth, FakeSupabase mocking, HTTPException assertions. Use when writing or reviewing backend/tests/test_*.py.

中文简介正在准备中。当前显示原文说明。

shanraisshan/learning-x-claude22026年5月7日 更新

Drive Chrome via the claude-in-chrome MCP to exercise plan.md::Verify steps for a shipped feature. Loads deferred MCP tool schemas, asserts console/network cleanliness, records a GIF for the PR. Used by the browser-verifier agent.

中文简介正在准备中。当前显示原文说明。

shanraisshan/learning-x-claude22026年5月7日 更新

Pre-PR code review checklist for this repo. Plan alignment, security gates, layering, dead code, API-surface completeness. Used by the code-reviewer agent.

中文简介正在准备中。当前显示原文说明。

shanraisshan/learning-x-claude22026年5月7日 更新

Build pages and components in the Next.js 15 App Router (RSC by default, "use client" only when needed), Tailwind for styling, typed props, and the existing CartProvider for cart state. Use when creating or modifying pages, layouts, components, or forms in frontend/.

中文简介正在准备中。当前显示原文说明。

shanraisshan/learning-x-claude22026年5月7日 更新

查看 shanraisshan 的全部技能

报告此技能的问题