新增接口必须显式调用c.bodyparser(&u)解析json请求体,传结构体地址并检查err;路径参数仅用于get,新增数据全走请求体;创建成功须返回201及location头,失败按语义返回409等状态码。

新增接口必须显式解析请求体,不能依赖自动绑定
Fiber 不会自动把 JSON 请求体反序列化到结构体,c.BodyParser() 必须手动调用,且传入变量地址。常见错误是写 c.BodyParser(user)(漏掉 &),结果解析静默失败,user 保持零值,后续插入数据库时字段全空或默认值。
正确做法:
- 定义结构体并加
json:tag,例如type User struct { Name string `json:"name"` Age int `json:"age"` } - 声明变量后传指针:
var u User; err := c.BodyParser(&u) - 检查
err—— 它可能是json.Unmarshal错误(如字段类型不匹配)、IO 错误,或空 body 导致的EOF - 别在中间件里提前调
c.Body()又不重置,否则BodyParser读不到内容
路径参数、查询参数和请求体别混用
新增操作几乎只用请求体(POST /users),但有人误把 ID 放路径(POST /users/123)或查询(POST /users?id=123),这违反 REST 约定,也增加校验负担。
明确分工:
-
c.Params("id"):只用于GET /users/:id这类路径参数,新增不用 -
c.Query("format"):只用于控制响应格式等可选行为,如?format=full,不参与业务数据 -
c.BodyParser():承载全部新增字段,包括客户端生成的 ID(如 UUID)、时间戳等 - 若需幂等性,
X-Idempotency-Key头必须由客户端传,服务端只校验不生成
插入后返回状态码和资源位置,别只丢个 200
HTTP 规范要求成功创建资源时返回 201 Created,并带 Location 响应头指向新资源 URL。只写 c.Status(200).JSON(...) 是错的,前端无法区分“更新成功”和“新增成功”。
实操要点:
- 插入成功后,用
c.Status(201)显式设状态码 - 调
c.Set("Location", "/users/"+newID),其中newID是数据库返回的主键或客户端传的 ID - 响应体仍可返回完整对象:
c.JSON(fiber.Map{"id": newID, "name": u.Name}) - 如果插入失败(如唯一约束冲突),不要返回 500,而应返回
409 Conflict并说明原因
事务与错误处理必须覆盖所有分支
新增接口常涉及多表插入或关联校验(如先查用户是否存在,再插订单),此时易漏事务回滚或错误分支响应。Fiber 的 return 不等于终止响应 —— 若没显式设状态码和响应体,后续代码仍可能执行并覆盖前值。
关键动作:
- 开启事务后,每个错误分支都必须调
tx.Rollback(),且不能只 defer(defer 在函数结束才执行,中间 panic 会跳过) - 每个 if/else 分支都要有明确响应:
c.Status(400).JSON(...)后紧跟return - 避免在 handler 里直接
log.Fatal或panic,这会中断整个 goroutine,应转为c.Status(500).SendString(...) - 数据库错误别原样透出(如
duplicate key),要映射为业务语义错误,比如 “手机号已被注册”
最常被忽略的是:插入成功后没验证数据库是否真写入了——比如用了 INSERT ... ON CONFLICT DO NOTHING 却没检查 RowsAffected(),导致前端以为新增成功,实际被忽略。这个判断点不在框架层,而在你调用 DB 驱动之后。











