快速开始
本章从零跑通 fun:装工具链 → fun new 脚手架 → 启动 → 调用 → 文档站在线调测 → 生成 TS 客户端 → 前端联调。
环境要求
| 工具 | 版本 | 说明 |
|---|---|---|
| Go | ≥ 1.26 | 框架模块声明 go 1.26.1 |
| Node.js | ≥ 18 | 仅前端 / 生成产物消费方需要 |
| fasthttp | v1.73.0 | 由 go get 自动带入 |
第一步:装 CLI 起项目
bash
go install github.com/cyi-cc/fun-cli@latest # fun 工具链(new/gen/docs/run)
fun new hello-fun # 生成 go.mod + hello world 示例服务
cd hello-fun && go run . # :18080 启动fun new 生成的 main.go 就是最小可运行示例——嵌入 fun.Ctx、导出方法即 RPC 端点:
go
type HelloDto struct {
Name string
}
type HelloSvc struct {
fun.Ctx
}
func (s *HelloSvc) Say(dto HelloDto) (string, error) {
return "hello, " + dto.Name + "!", nil
}不用脚手架?手动搭建
bash
mkdir hello-fun && cd hello-fun
go mod init hello-fun
go get github.com/cyi-cc/fun@latest然后照上面的结构写 main.go:f := fun.New(); f.BindService(&HelloSvc{}); f.Start(18080)。
用 curl 调用
所有业务请求都是 POST /cell,body 指定服务与方法(注册名首字母小写):
bash
curl -X POST http://localhost:18080/cell \
-H 'Content-Type: application/json' \
-d '{"serviceName":"helloSvc","methodName":"say","data":{"name":"fun"}}'响应是统一的 Result,所有键递归转首字母小写:
json
{"status":0,"data":"hello, fun!"}字段名大小写不敏感:请求里写 "name" 或 "Name" 都能匹配到 HelloDto.Name。
在线调测:fun docs
bash
fun docs # :7788 文档站——服务/方法树、参数表单、在线发送改代码自动重建后端 + 刷新元数据(热更新);方法与字段说明可编辑落盘, 标题旁一键复制带请求体的分享深链。完整用法见 fun-cli。
完整示例:仓库自带的 demo
example/demo 演示了全部核心特性——定宽整型与可空指针字段、枚举、业务错误码、类型化流式:
go
// OrderStatus 订单状态枚举:uint8 底层 + Names/DisplayNames
type OrderStatus uint8
func (OrderStatus) Names() []string { return []string{"Pending", "Paid", "Shipped"} }
func (OrderStatus) DisplayNames() []string { return []string{"待支付", "已支付", "已发货"} }
type CreateOrderDto struct {
Sku string // 必传
Count int64 // 必传
Note *string // 可空
Status *OrderStatus // 可空,缺省 Pending
Tags []string // 可省略
}
type OrderSvc struct {
fun.Ctx
}
func (s *OrderSvc) Create(dto CreateOrderDto) (OrderDto, error) {
return OrderDto{Id: 9007199254740993, Status: OrderStatus(0), Amount: "199.00"}, nil
}
// Cancel error-only 签名:无返回数据
func (s *OrderSvc) Cancel(dto CancelDto) error {
if dto.Reason == nil {
return fun.Error(4004, "必须填写取消原因") // status=2,code/msg 原样透传
}
return nil
}生成对应客户端产物的命令在 cmd/genexample,产物见 example/gen。
生成 TypeScript 客户端
bash
fun gen ts -o frontend/src/api # 自动扫描 BindService 采集元数据,一步出产物产物落在 <out>/ts/ 子目录,fun.ts 是聚合入口:
ts
import { api } from './api/ts/fun'
const c = api.create('/api')
c.setState({ token: 'xxx' }) // 每个请求自动带上 state
const r = await c.helloSvc.say({ name: 'fun' })
if (r.status === 0) {
console.log(r.data) // "hello, fun!",响应键已转小写,类型直达
}不用 CLI?手动写 cmd/gen
建一个 cmd/gen,用 BindServiceForGen 代替 BindService——只登记类型元信息,不装配任何基础设施(数据库、Redis 无需运行):
go
// cmd/gen/main.go
package main
import (
"fmt"
"github.com/cyi-cc/fun"
"hello-fun" // 引入你的服务定义
)
func main() {
f := fun.New()
f.BindServiceForGen(&HelloSvc{})
fun.SetOutput("./frontend/src/api") // ⚠️ 会清空整个输出目录
fun.GenCode(fun.GenTs{}) // 也可加 fun.GenGo{} 同时生成 Go 客户端
fmt.Println("生成完成")
}bash
go run ./cmd/gen前端联调(Vite 代理)
后端只有 /cell 一个路径,vite 代理需要把前缀重写掉:
js
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://localhost:18080',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/api/, ''),
},
},
},
}客户端 api.create('/api'),实际请求 POST /api/cell → 代理转给后端 /cell。
浏览器直连(无代理)场景改用服务端 CORS 白名单。
常见的「第一步」错误
| 现象 | 原因 |
|---|---|
启动即 panic:Unsupported types int | DTO 用了普通 int/uint、float、map 等非法类型,见 DTO 规则 |
运行期报 must be a pointer or have a corresponding field | 非指针、非 slice 的 DTO 字段漏传或传了 null |
客户端报 method not found | 方法名首字母小写(未导出),不会注册为端点 |
| 前端取不到字段 | 响应键已全部转首字母小写,按 camelCase 取值 |
更多见常见问题。
下一步
- fun-cli 命令行:
new/gen/docs/run全量速查 - 服务与服务注册:三种方法签名与依赖注入
- 线协议与错误处理:
status语义与fun.Error - TS 客户端使用:拦截器、AbortSignal、流式重连