MuseMVP 文档
API

Backend 指南

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

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

src/backend 目录快速地图

目录职责典型文件
src/backend/apiHono API 入口、路由、中间件、OpenAPIapi/app.ts、api/routes/*、api/middleware/*
src/backend/api-client前端可复用 API 调用层(含 hooks 与 server helper)api-client.ts、admin/use-admin.ts、auth/use-auth-server.ts
src/backend/authBetter-Auth 服务端/客户端配置auth/auth.ts、auth/client.ts
src/backend/database绑定本应用 driver/schema 的查询包装database/client.ts、database/schema.ts、database/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。

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

Handler 调用 feature service,再通过应用 database 包装调用包级 query。

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


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

客户端(Client Component)优先用 hooks

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

"use client";

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

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

  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):

业务编排放在 feature service;保留 getSessionState() 的三态和数据库异常,不在组件里用 contracts.length 猜计费权益。

  1. 必须从服务端调用 /api/* 时,显式透传 cookie(常见于 NextRequest 场景):
import type { NextRequest } from "next/server";
import { getBaseUrl } from "@musemvp/shared";

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();
}

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

在 packages/db/src/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 检查接口描述是否符合预期。


本页目录