Rapina 后端API框架配套前端代码编写指南
先明确核心:Rapina 是 Rust 后端API框架,本身不提供前端渲染能力,只输出标准 JSON + 自动生成 OpenAPI 接口文档;前端独立开发(Vue/React/原生JS等),通过 HTTP 请求调用 Rapina 接口。
官网 userapina.com 是 Rapina 项目官网,仅展示后端用法,无内置前端模板,但框架提供两大关键能力简化前端对接:
- 自动生成 OpenAPI 规范(可导入Swagger/Postman/前端TS类型生成器)
- 统一标准化错误返回、JWT鉴权规则、请求校验结构
一、前置:Rapina 后端接口约定(前端必须遵守)
1. 鉴权规则(核心)
- 所有路由默认需要JWT鉴权,仅标记
#[public]接口无需token - JWT 传递方式:请求头
Authorization: Bearer {token} - 未携带/过期token:统一返回401结构化错误,带
trace_id
{
"error": {
"code": "UNAUTHORIZED",
"message": "missing or invalid jwt token",
"details": []
},
"trace_id": "uuid字符串"
}
2. 请求校验格式(422错误)
使用 Validated<Json<T>> 的接口,参数不合法会提前拦截,返回统一结构:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{"field": "email", "message": "invalid email"},
{"field": "password", "message": "min 8 chars"}
]
},
"trace_id": "xxx"
}
3. 成功响应规范
后端返回 Json<T> 直接输出对象,无多余包装(健康接口直接返回纯文本 ok)
示例登录返回:
{"token": "jwt字符串", "expires_at": 1789000000}
4. 全局 trace_id
所有请求响应携带 trace_id,前端日志必须打印,方便后端排查线上问题。
二、方案1:原生JS/HTML 极简前端示例
对接 Rapina 登录、获取当前用户、健康检查接口
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Rapina API Demo</title>
</head>
<body>
<div id="app">
<h3>登录</h3>
<input type="email" id="email" placeholder="邮箱">
<input type="password" id="pwd" placeholder="密码">
<button onclick="login()">登录</button>
<h3>我的信息</h3>
<button onclick="getMe()">获取用户</button>
<div id="result"></div>
</div>
<script>
const BASE_URL = "http://localhost:3000";
// 全局统一请求封装,自动携带JWT、统一错误处理
async function request(path, options = {}) {
const token = localStorage.getItem("rapina_token");
const headers = {
"Content-Type": "application/json",
...options.headers
};
// 非公开接口自动附加鉴权头
if (token) headers.Authorization = `Bearer ${token}`;
const res = await fetch(`${BASE_URL}${path}`, {
...options,
headers
});
const data = await res.json();
// 统一错误拦截
if (!res.ok) {
console.error("请求异常 trace_id:", data.trace_id, data.error);
// 401 自动清除token跳登录
if (res.status === 401) {
localStorage.removeItem("rapina_token");
alert("登录失效,请重新登录");
}
throw new Error(data.error.message);
}
return data;
}
// 1. 公开接口:健康检查 #[public]
async function healthCheck() {
const res = await fetch(`${BASE_URL}/health`);
console.log("服务状态:", await res.text());
}
// 2. 登录接口 #[public] /login
async function login() {
const email = document.getElementById("email").value;
const password = document.getElementById("pwd").value;
try {
const tokenData = await request("/login", {
method: "POST",
body: JSON.stringify({ email, password })
});
// 存储JWT
localStorage.setItem("rapina_token", tokenData.token);
alert("登录成功");
} catch (err) {
document.getElementById("result").innerText = err.message;
}
}
// 3. 需鉴权接口 /me
async function getMe() {
try {
const user = await request("/me");
document.getElementById("result").innerText = JSON.stringify(user, null, 2);
} catch (err) {
document.getElementById("result").innerText = err.message;
}
}
healthCheck();
</script>
</body>
</html>
三、方案2:Vue3 + Axios 工程化前端(主流)
1. 请求封装 src/utils/rapinaRequest.js
import axios from "axios";
const service = axios.create({
baseURL: "http://localhost:3000",
timeout: 10000
});
// 请求拦截器:自动注入JWT
service.interceptors.request.use(config => {
const token = localStorage.getItem("rapina_token");
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
// 响应拦截器:统一处理Rapina标准错误
service.interceptors.response.use(
res => res.data,
err => {
const resData = err.response?.data;
if (resData?.trace_id) {
console.error("Rapina请求报错 trace_id:", resData.trace_id, resData.error);
}
// 401 清除登录态
if (err.response.status === 401) {
localStorage.removeItem("rapina_token");
router.push("/login");
}
// 校验错误弹窗展示字段信息
if (resData?.error?.code === "VALIDATION_ERROR") {
const msg = resData.error.details.map(i => `${i.field}:${i.message}`).join(";");
ElMessage.error(msg);
} else {
ElMessage.error(resData?.error?.message || "接口请求失败");
}
return Promise.reject(err);
}
);
export default service;
2. API 接口分层 src/api/user.js
import request from "@/utils/rapinaRequest";
// 登录 公开接口
export function loginApi(data) {
return request({
url: "/login",
method: "post",
data
});
}
// 创建用户
export function createUserApi(data) {
return request({
url: "/users",
method: "post",
data
});
}
// 获取当前登录用户
export function getMeApi() {
return request({ url: "/me", method: "get" });
}
// 根据ID查询用户
export function getUserByIdApi(id) {
return request({ url: `/users/${id}`, method: "get" });
}
// 健康检查
export function healthApi() {
return request({ url: "/health", method: "get" });
}
3. 页面组件调用示例
<script setup>
import { loginApi } from "@/api/user";
const loginForm = ref({ email: "", password: "" });
const submitLogin = async () => {
const tokenInfo = await loginApi(loginForm.value);
localStorage.setItem("rapina_token", tokenInfo.token);
};
</script>
四、方案3:React + Typescript(推荐,配合OpenAPI生成类型)
1. 利用 Rapina 自动 OpenAPI 生成TS类型
Rapina 内置 OpenAPI 文档,访问 http://localhost:3000/openapi.json 下载规范文件
使用工具 openapi-typescript 一键生成前端接口类型:
# 安装工具
npm i -D openapi-typescript
# 生成类型文件
npx openapi-typescript http://localhost:3000/openapi.json -o src/types/rapinaApi.ts
生成后直接拥有 LoginRequest、User、CreateUser 等后端结构体对应的TS类型,前后端类型完全统一,杜绝参数拼写错误。
2. Axios + TS 请求封装核心片段
import axios from "axios";
import type { paths } from "@/types/rapinaApi";
const api = axios.create({ baseURL: "http://localhost:3000" });
// 登录接口类型约束
export const login = async (body: paths["/login"]["post"]["requestBody"]["content"]["application/json"]) => {
const res = await api.post("/login", body);
return res.data as paths["/login"]["post"]["responses"]["200"]["content"]["application/json"];
};
五、关键开发优化技巧
1. 区分公开/鉴权接口
- 带
#[public](/health、/login):无需token,前端直接请求 - 无
#[public](/me、/users/:id):请求头必须携带Bearer token,封装层自动处理,无需手动写
2. 统一处理校验错误
Rapina 会提前校验入参,返回固定 details 数组,前端循环遍历展示表单错误,不用自己写校验逻辑:
// 提取表单错误
const errMap = {};
resData.error.details.forEach(item => {
errMap[item.field] = item.message;
});
3. 部署与跨域配置
Rapina 内置 CORS 支持,后端可配置允许前端域名,避免跨域报错;单二进制部署,前端打包静态资源可直接通过 Rapina 托管静态文件。
4. 调试工具
rapina routes命令查看所有接口路径、是否公开- 访问后端
/docs打开自动生成的 Swagger UI,在线调试接口,复制请求示例 trace_id全链路追踪,前端埋点打印,后端日志快速定位报错请求
六、常见前端踩坑点
- 忘记携带Token:所有非
#[public]接口401报错,统一在请求拦截器自动附加token - 请求体格式错误:Rapina 使用 Json 序列化,前端必须传
Content-Type: application/json - 路径参数格式:
/users/:id后端强类型校验,传数字字符串/非法ID会直接返回校验错误 - 密码长度、邮箱格式:后端使用
Validate宏拦截,前端建议同步做基础预校验提升体验 - token过期:后端返回401,前端清空本地存储并跳转登录页
七、极简前端技术栈推荐
- 快速原型:原生HTML+Fetch(无需构建工具)
- 后台管理:Vue3 + Element Plus + Axios
- 大型项目:React + TS + OpenAPI自动类型生成 + React Query
- 移动端:UniApp / Taro,请求封装逻辑和Web端完全通用

浙公网安备 33010602011771号