快速开始

从零到能 curl 的服务只要一条命令;加数据库不需要装 Docker;要真依赖时再 make dev。三步可以停在任意一步。

前置条件

git clone https://github.com/smallnest/matex.git && cd matex
go mod download

第一步:零依赖起步

configs/config.min.yaml 里只有 http、log 与 服务自己的段。启动不连接任何外部服务:

make run-min

# 另开一个终端
curl -i localhost:8080/healthz
curl -i localhost:8080/api/v1/hello/world

预期看到:

$ curl -s localhost:8080/api/v1/hello/world
{"code":0,"msg":"ok","data":{"greeting":"hello, world"}}
响应封套是固定的 成功是 {code:0,msg:"ok",data:…},失败是 {code:业务码,msg:"…",data:null} 加对应 HTTP 状态。 handler 返回 nil, nil 时为 204,没有响应体。

第二步:带数据库,但依然零外部依赖

默认驱动是纯 Go SQLite(modernc.org/sqlite):不需要 cgo、不需要 Docker、 不需要网络。迁移按文件名顺序执行,追加不修改。

make migrate DRIVER=sqlite DSN=file:matex.db
make run-sqlite

curl -i localhost:8080/api/v1/hello/world
curl -i localhost:8080/api/v1/hello/stats/world   # 计数来自数据库

第三步:接真实依赖

make dev 用 docker compose 起 postgres / mysql / redis / memcache / kafka, 然后换成完整配置:

make dev
make migrate DSN=postgres://matex:matex@localhost:5432/matex?sslmode=disable
make run

# 用完停掉
make dev-down
只挂环境变量是不够的 基础设施是"配了才建"——要让 db / redis / kafka 生效,配置里必须有对应的段。 只给 DB_DSN 环境变量但没有 db: 段,服务不会去连数据库。 Docker 镜像默认拷的是 config.min.yaml,需要这些能力时挂载完整配置。

三份配置的关系

文件 内容 用途
configs/config.min.yaml http + log + 服务段 零依赖启动,也是镜像默认配置
configs/config.sqlite.yaml 加 db: driver: sqlite 带库但零外部依赖
configs/config.yaml 含 db / redis / memcache / kafka 段 本地全量、真实部署

跑测试与示例

全部测试与全部例子都不需要 Docker,因此可以在 CI 里一次跑完:

make test-short      # 快速测试(含 sqlite DB 用例,带 -race)
make test            # 全量测试
make ci              # vet + test-short + build(提交前跑这个)
go test ./examples/...   # 20 个示例的测试,全部离线

make example NAME=http   # 跑某个示例,等价于 go run ./examples/http

看到日志,就对了

服务启动后每个请求都有一行结构化日志,带 trace id。这条 trace id 也会回写到响应头 X-Request-ID,所以不接链路后端也能把一次调用串起来:

$ curl -si localhost:8080/api/v1/hello/world | grep -i x-request-id
X-Request-ID: 4f2a9c1e8b7d3a05

$ # 服务端日志
{"time":"…","level":"INFO","msg":"http","trace_id":"4f2a9c1e8b7d3a05",
 "method":"GET","path":"/api/v1/hello/world","code":200,"dur_ms":0}

下一步读什么

架构总览 搞清楚启动时每一步做了什么,以及为什么是这个顺序。 示例索引 20 个能力各一个可运行示例,挑你正在做的那个看。 写第一个接口 handler 约定、路由注册、错误怎么变成状态码。