Skip to content

快速开始 ​

本章从零跑通 fun:装工具链 → fun new 脚手架 → 启动 → 调用 → 文档站在线调测 → 生成 TS 客户端 → 前端联调。

环境要求 ​

工具版本说明
Go≥ 1.26框架模块声明 go 1.26.1
Node.js≥ 18仅前端 / 生成产物消费方需要
fasthttpv1.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 intDTO 用了普通 int/uint、float、map 等非法类型,见 DTO 规则
运行期报 must be a pointer or have a corresponding field非指针、非 slice 的 DTO 字段漏传或传了 null
客户端报 method not found方法名首字母小写(未导出),不会注册为端点
前端取不到字段响应键已全部转首字母小写,按 camelCase 取值

更多见常见问题。

下一步 ​

基于 MIT 许可发布