# portal-mini-go 小程序端接口文档 > 基于 Go + gin 的微信小程序后端服务。本文档描述**小程序端(`/api/ma`)**相关接口。后台管理接口见 `admin-api.md`。 ## 1. 概述 - **基础路径**:`/api/ma` - **服务地址**:由 `configs/config.yaml` 中 `server.port` 决定(默认 `8080`),例如 `http://localhost:8080`。 - **统一响应**:所有接口均返回 `HTTP 200`,业务结果通过响应体中的 `code` 字段判断(见 §2.4)。 - **鉴权方式**:小程序端所有接口需在请求头携带 `X-App-ID`,由 `MiniAppAuth` 中间件校验该小程序是否被纳管且启用。 - **全局接口**:`GET /healthz` 为健康检查,无需鉴权,返回 `{"code":0,"msg":"ok","data":{"status":"ok"}}`。 ## 2. 公共约定 ### 2.1 请求头 | Header | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 是(POST/PUT) | 固定为 `application/json`。 | | `X-App-ID` | 是 | 微信小程序的 AppID,标识调用方小程序身份;必须对应一个「已启用且未删除」的被纳管小程序。 | | `Authorization` | 否(登录态接口必填) | 用户会话凭证,格式 `Bearer `;也可使用 `X-Session-Token: `。由 `login` 下发,用于识别当前登录用户。 | ### 2.2 统一响应结构 ```json { "code": 0, "msg": "ok", "data": { } } ``` | 字段 | 类型 | 说明 | | --- | --- | --- | | `code` | int | 业务码。`0` 表示成功;非 `0` 表示失败(见 §2.4)。 | | `msg` | string | 结果描述。`0` 时为 `ok`,失败时为人可读信息。 | | `data` | object/null | 业务数据,成功时有内容,失败时通常省略。 | ### 2.3 鉴权中间件 | 中间件 | 校验逻辑 | | --- | --- | | `MiniAppAuth` | 校验请求头 `X-App-ID` 对应一个「已启用且未删除」的被纳管小程序;通过后将 `app_id` 与小程序主键 `mini_id` 注入上下文,供后续 handler/service 使用。 | | `MiniUserAuth` | 校验用户会话 token(`Authorization: Bearer ` 或 `X-Session-Token`),经 `session.Store` 解析出当前用户主键 `user_id` 并注入上下文。**必须在 `MiniAppAuth` 之后使用**,依赖其注入的 `mini_id` 确保会话归属到正确的小程序。token 无效/过期返回 `40100`。 | > 全局还挂载 `Recovery`(panic 恢复)、`Trace`(注入 trace_id)、`ErrorHandler`(统一错误转换)。错误由中间件转换,handler 内不直接散落 `c.JSON` 处理错误。 ### 2.4 错误码 | 业务码 | 常量 | 含义 | | --- | --- | --- | | `0` | — | 成功 | | `40000` | `ErrBadRequest` | 请求参数错误 / 非法输入 | | `40100` | `ErrUnauthorized` | 未认证 / 登录失败 / token 无效或过期 | | `40300` | `ErrForbidden` | 禁止访问 | | `40400` | `ErrNotFound` | 资源不存在 / 小程序未注册(如 `X-App-ID` 无效) | | `50000` | `ErrServer` | 服务内部错误(含微信调用、会话写入等) | > 非 `BizError` 的未知错误一律归为 `50000`。 ## 3. 接口列表 ### 3.1 `POST /api/ma/login` 小程序登录:通过微信 `code2session` 换取 `openid`/`unionid`,落库用户并向客户端下发会话 token。 **请求头** ``` X-App-ID: <微信小程序 AppID> ``` **请求体** ```json { "code": "081abc..." // 必填,微信登录 code } ``` | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `code` | string | 是 | 小程序 `wx.login` 获取的临时登录 code。 | **响应** ```json { "code": 0, "msg": "ok", "data": { "token": "a1b2c3...48位hex字符串", "user": { "id": 1, "openid": "oABC...", "union_id": "oXYZ...", "nickname": "", "avatar": "", "created_at": 1698211200 } } } ``` > `token` 为 `24` 字节随机值的 hex 编码(48 字符),对应会话保留 `7` 天。后续小程序业务接口需在请求头携带 `Authorization: Bearer `(或 `X-Session-Token: `),由 `MiniUserAuth` 中间件解析当前用户身份。 > `user` 为 `ProfileView`:`created_at` 为 Unix 秒级时间戳;不含 `mini_id`/`updated_at`,且返回的是当前用户自身数据(含 `openid`/`union_id`)。 **curl 示例** ```bash curl -X POST http://localhost:8080/api/ma/login \ -H "Content-Type: application/json" \ -H "X-App-ID: wx1234567890" \ -d '{"code":"081abc..."}' ``` ### 3.2 `POST /api/ma/logout` 注销当前用户会话:删除 `login` 下发的会话 token,使该 token 立即失效。 **请求头** ``` X-App-ID: <微信小程序 AppID> Authorization: Bearer ``` **响应** ```json { "code": 0, "msg": "ok", "data": null } ``` > 需在 `MiniUserAuth` 之后调用;token 缺失/无效返回 `40100`。 **curl 示例** ```bash curl -X POST http://localhost:8080/api/ma/logout \ -H "X-App-ID: wx1234567890" \ -H "Authorization: Bearer a1b2c3..." ``` --- ### 3.3 `GET /api/ma/profile` 获取当前登录用户资料(自身数据,含 `openid`/`union_id`)。 **请求头** ``` X-App-ID: <微信小程序 AppID> Authorization: Bearer ``` **响应** ```json { "code": 0, "msg": "ok", "data": { "id": 1, "openid": "oABC...", "union_id": "oXYZ...", "nickname": "张三", "avatar": "https://...", "created_at": 1698211200 } } ``` > 返回结构为 `ProfileView`(`created_at` 为 Unix 秒级时间戳)。用户身份由 `MiniUserAuth` 从 token 解析,查询强制按 `mini_id` 过滤,杜绝跨小程序访问。 **curl 示例** ```bash curl http://localhost:8080/api/ma/profile \ -H "X-App-ID: wx1234567890" \ -H "Authorization: Bearer a1b2c3..." ``` --- ### 3.4 `PUT /api/ma/profile` 修改当前登录用户的昵称/头像。留空的字段不更新(支持部分更新)。 **请求头** ``` X-App-ID: <微信小程序 AppID> Authorization: Bearer Content-Type: application/json ``` **请求体** ```json { "nickname": "新昵称", "avatar": "https://new-avatar.png" } ``` | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `nickname` | string | 否 | 新昵称;为空则不更新。 | | `avatar` | string | 否 | 新头像 URL;为空则不更新。 | **响应** ```json { "code": 0, "msg": "ok", "data": null } ``` > 用户身份由 `MiniUserAuth` 解析;更新限定在 `mini_id` 范围内,目标用户不存在返回 `40400`。 **curl 示例** ```bash curl -X PUT http://localhost:8080/api/ma/profile \ -H "Content-Type: application/json" \ -H "X-App-ID: wx1234567890" \ -H "Authorization: Bearer a1b2c3..." \ -d '{"nickname":"新昵称"}' ``` --- ### 3.5 `GET /api/ma/users/:id` 获取同小程序下指定用户的公开信息(仅 `id`/`nickname`/`avatar`,剔除 `openid`/`union_id` 等敏感字段)。 **请求头** ``` X-App-ID: <微信小程序 AppID> Authorization: Bearer ``` **路径参数** | 参数 | 类型 | 说明 | | --- | --- | --- | | `id` | uint64 | 目标用户主键。 | **响应** ```json { "code": 0, "msg": "ok", "data": { "id": 2, "nickname": "李四", "avatar": "https://..." } } ``` > 返回结构为 `PublicUserView`。查询按 `mini_id` 过滤,目标用户不存在或不属于该小程序返回 `40400`。 **curl 示例** ```bash curl http://localhost:8080/api/ma/users/2 \ -H "X-App-ID: wx1234567890" \ -H "Authorization: Bearer a1b2c3..." ``` --- ### 3.6 `GET /api/ma/users` 分页列出同小程序下的用户(公开字段)。 **请求头** ``` X-App-ID: <微信小程序 AppID> Authorization: Bearer ``` **查询参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | | --- | --- | --- | --- | --- | | `page` | int | 否 | `1` | 页码,从 1 开始。 | | `size` | int | 否 | `20` | 每页条数,范围 `1`~`100`,超出则按 `20` 处理。 | **响应** ```json { "code": 0, "msg": "ok", "data": { "list": [ { "id": 1, "nickname": "张三", "avatar": "https://..." }, { "id": 2, "nickname": "李四", "avatar": "https://..." } ], "total": 100, "page": 1, "size": 20 } } ``` > 返回结构为 `PublicUserView` 数组(已剔除敏感字段)。列表按 `id` 倒序,查询按 `mini_id` 过滤。 **curl 示例** ```bash curl "http://localhost:8080/api/ma/users?page=1&size=20" \ -H "X-App-ID: wx1234567890" \ -H "Authorization: Bearer a1b2c3..." ``` --- ## 4. 数据模型 ### 4.1 User(小程序用户) | 字段 | 类型 | JSON | 说明 | | --- | --- | --- | --- | | `ID` | uint64 | `id` | 主键,自增。 | | `MiniID` | uint64 | `mini_id` | 所属小程序主键(关联 `mini_programs.id`)。 | | `OpenID` | string | `openid` | 微信 openid。 | | `UnionID` | string | `union_id` | 微信 unionid(可为空)。 | | `Nickname` | string | `nickname` | 昵称。 | | `Avatar` | string | `avatar` | 头像 URL。 | | `CreatedAt` | time | `created_at` | 创建时间。 | | `UpdatedAt` | time | `updated_at` | 更新时间。 | > 用户由 `(mini_id, open_id)` 唯一标识。 ## 5. 备注与后续扩展 - **多小程序**:新增 `app2`..`app10` 时,按 `internal/handler/miniapp/app1`、`internal/service/miniapp/app1` 的目录结构各自建包,在 `router.New` 中注册即可,互不耦合。新增小程序后须在本文档补充其接口。 - **会话存储**:默认 `MemoryStore`(单实例),多实例部署应替换为 Redis 实现(复用 `session.Store` 接口)。 - **业务接口**:`/api/ma` 已实现 `login`/`logout`、用户资料查询与修改(`/profile`)、按 ID 查询用户(`/users/:id`)与用户分页列表(`/users`)。新增业务接口时,应在路由中增加基于会话 token 的用户身份中间件(`MiniUserAuth`)后再登记,并同步更新本文档 §3。