MuseMVP 文档
API 接口

Backend 指南

src/backend 实战指南:目录职责、api-client 在客户端/服务端的使用方式,以及完整请求链路。

这篇文档聚焦 MuseMVP 模板二次开发:重点不是讲概念,而是告诉你在这个代码库里“应该改哪里、怎么接链路”。

src/backend 目录快速地图

目录职责典型文件
src/backend/apiHono API 入口、路由、中间件、OpenAPIapi/app.tsapi/routes/*api/middleware/*
src/backend/api-client前端可复用 API 调用层(含 hooks 与 server helper)api-client.tsadmin/use-admin.tsauth/use-auth-server.ts
src/backend/authBetter-Auth 服务端/客户端配置auth/auth.tsauth/client.ts
src/backend/databaseDrizzle 连接、schema、queriesdatabase/client.tsdatabase/schema.tsdatabase/queries/*

关键边界

src/backend 负责“通用后端能力”;业务编排优先放在 src/modules/<feature>/lib/*,由 API 路由层调用。


一条请求是怎么走完的

客户端组件发起请求(通常通过 src/backend/api-client/* hooks)。

请求进入 /api/*,由 src/app/api/[[...rest]]/route.ts 转发给 Hono。

src/backend/api/app.ts 先执行全局中间件(logger、CORS),再匹配具体 router。

路由级中间件(如 authMiddlewareadminMiddleware)执行,handler 完成参数校验与响应封装。

Handler 调用 service(src/modules/*)或 query(src/backend/database/queries/*)。

数据库返回结果,响应回到前端;若是 mutation,前端用 TanStack Query 做缓存失效。


api-client 怎么用(客户端 vs 服务端)

客户端(Client Component)优先用 hooks

你会拿到现成的 query/mutation hooks(例如 useAdminUsersQueryuseAvatarUploadMutation),这是默认推荐方式:

"use client";

import { useAdminUsersQuery } from "@/backend/api-client/admin/use-admin";

export function AdminUsersPanel() {
  const { data, isLoading, error } = useAdminUsersQuery({
    itemsPerPage: 10,
    currentPage: 1,
    searchTerm: "",
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Load failed</div>;

  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

如果要写新 hook,复用 apiClient + InferRequestType,避免手写请求类型:

import { useMutation } from "@tanstack/react-query";
import type { InferRequestType } from "hono";
import { apiClient } from "@/backend/api-client/api-client";

type ContactForm = InferRequestType<typeof apiClient.contact.$post>["form"];

export function useContactSubmit() {
  return useMutation({
    mutationFn: async (form: ContactForm) => {
      const res = await apiClient.contact.$post({ form });
      if (!res.ok) throw new Error("Submit failed");
    },
  });
}

服务端(Server Component / Route Handler)有两种策略

  1. 同仓单体场景优先“直连服务/查询”(不绕一层 HTTP):
import { getSession } from "@/backend/api-client/auth/use-auth-server";
import { getActiveMuseBillingContractsByUserId } from "@/backend/database";

export async function getCurrentUserProState() {
  const session = await getSession();
  if (!session?.user?.id) return { hasProAccess: false };

  const contracts = await getActiveMuseBillingContractsByUserId(session.user.id);
  return { hasProAccess: contracts.length > 0 };
}
  1. 必须从服务端调用 /api/* 时,显式透传 cookie(常见于 NextRequest 场景):
import type { NextRequest } from "next/server";
import { getBaseUrl } from "@/lib/get-base-url";

export async function getMuseAccessStatusForSession(req: NextRequest) {
  const response = await fetch(`${getBaseUrl()}/api/muse-billing/access`, {
    headers: {
      cookie: req.headers.get("cookie") || "",
    },
  });

  if (!response.ok) return null;
  return response.json();
}

新增一个业务接口的推荐流程

src/backend/database/queries/* 写数据读写函数(只做 DB 访问)。

src/modules/<feature>/lib/* 写业务编排(规则、状态流转、异常处理)。

src/backend/api/routes/<feature>/* 写 Hono 路由:validator + middleware + handler。

src/backend/api/app.ts 注册 router。

src/backend/api-client/<feature>/* 提供前端调用 hook,并在 mutation 后做 invalidateQueries

/api/openapi/api/docs 检查接口描述是否符合预期。