spark-server/internal/transport/http/docs/openapi.yaml
zhr ae9a71034d feat: implement Spark IM V3 modular monolith
Add HTTP /v1 MVC, TCP send path, groups with server-side member-avatar collage, object-storage upload, and friends/favorites around the architecture-v3 layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 19:52:11 +08:00

1155 lines
34 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

openapi: 3.0.3
info:
title: Spark IM API
version: 0.1.0
description: |
本页是 **HTTP REST**(Gin `127.0.0.1:8080`)。长连接 IM 是另一套 TCP,见文末。
## 响应
```json
{"code":"0","msg":"ok","data":{}}
```
`code` 是字符串。`"0"` 成功,其它失败。失败时 `data` 为 `{}`。看 `code`,不要只看 HTTP 状态(多数接口 HTTP 200;`/readyz` 未就绪才是 503)。
## 鉴权
1. `POST /v1/auth/login` 拿 `access_token` / `refresh_token`。测试号 `test01@spark.com`~`test10@spark.com`,`verify_code` 任意。
2. 其它接口:`Authorization: Bearer <access_token>`。
3. 可选 `X-Device-ID` 必须等于登录时的 `device_id`,否则 `40101`。
4. 续期 `POST /v1/auth/token/refresh`(用 refresh,不必带 Bearer)。退出 `POST /v1/auth/logout`。
语言:`X-Language` 优先,否则 `Accept-Language`。取值 `zh-CN`(默认)/ `en` / `zh-TW`。
## TCP(不是 Protobuf)
二进制 Frame 头 23 字节(Magic `SP` + Command + SequenceID + BodyLength),**Body 是上面同一套 JSON**。没有 `.proto`,不要按 Protobuf 解包。
公网 TLS 在 Nginx `:443` 终结;gnet 只收本机 PROXY 明文。心跳 / AUTH / GENERATE_MSG_ID 已通;发消息与同步还在接。
servers:
- url: http://127.0.0.1:8080
description: loopback HTTP (not public)
security:
- bearerAuth: []
tags:
- name: system
- name: auth
- name: users
- name: friends
- name: groups
- name: conversations
- name: messages
- name: files
- name: favorites
paths:
/healthz:
get:
tags: [system]
security: []
summary: 进程探活
operationId: healthz
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
example:
code: "0"
msg: ok
data:
status: ok
/readyz:
get:
tags: [system]
security: []
summary: 就绪探活(MySQL / Redis / 是否接流量)
description: |
进程存活用 `/healthz`(始终 200)。
`/readyz` 在未接流量、依赖不可用或关停中返回 HTTP 503,`code=50301`。
Nginx / 编排应摘流看本接口,不要看 `/healthz`。
operationId: readyz
responses:
"200":
description: 已就绪
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
example:
code: "0"
msg: ok
data:
status: ok
accepting: true
mysql: ok
redis: ok
taskpool: ok
"503":
description: 未就绪
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
example:
code: "50301"
msg: 服务不可用
data:
status: not_ready
accepting: false
mysql: skipped
redis: skipped
taskpool: ok
/docs:
get:
tags: [system]
security: []
summary: OpenAPI 文档页(Swagger UI)
operationId: docsUI
responses:
"200":
description: HTML
content:
text/html:
schema:
type: string
/openapi.yaml:
get:
tags: [system]
security: []
summary: OpenAPI 规范原文
operationId: openAPISpec
responses:
"200":
description: YAML
content:
application/yaml:
schema:
type: string
/v1/auth/email-codes:
post:
tags: [auth]
security: []
summary: 发送邮箱登录验证码
description: |
验证码 5 分钟有效,同一邮箱 60 秒内只能发一次。
测试账号 `test01@spark.com`~`test10@spark.com` 无需发码,登录时任意填写 `verify_code`。
当前不发送真实邮件,验证码写入 Redis(无 Redis 时为进程内存)。
operationId: sendEmailCode
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SendEmailCodeRequest"
example:
email: ada@example.com
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
examples:
ok:
value:
code: "0"
msg: ok
data:
expires_in: 300
/v1/auth/login:
post:
tags: [auth]
security: []
summary: 邮箱验证码登录并签发 JWT
description: |
首次验证成功会创建用户(Snowflake uid、默认 spark_id、shortid 个人二维码票据,不含 uid)。
登录写入/更新 `user_devices`(device_type 存在 `platform` 列、device_name、app_version、language、last_ip),并追加 `user_login_logs`。
返回 access_token 与 refresh_token。测试账号任意验证码即可。
`device_type` 必填:ios / android / harmony / windows / macos / web(也接受旧字段 `platform`)。
operationId: login
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/LoginRequest"
example:
email: test01@spark.com
verify_code: "000000"
device_id: 7
device_type: ios
device_name: iPhone
responses:
"200":
description: 统一 envelope。成功时 data 为 LoginData;失败时 data 为 {}
content:
application/json:
schema:
$ref: "#/components/schemas/LoginEnvelope"
examples:
ok:
value:
code: "0"
msg: ok
data:
access_token: eyJhbGciOiJIUzI1NiJ9...
refresh_token: eyJhbGciOiJIUzI1NiJ9...
expires_in: 604800
refresh_expires_in: 2592000
user_id: 1940000000000000000
device_id: 7
spark_id: s1a2b3c
unauthorized:
value:
code: "40101"
msg: 未授权
data: {}
invalid:
value:
code: "40001"
msg: 请填写验证码
data: {}
/v1/auth/token/refresh:
post:
tags: [auth]
security: []
summary: 用 refresh_token 续期
description: |
校验 refresh_token 后签发新的 access/refresh,旧一对立即失效(jti denylist)。
不需要 access Bearer。按 RealIP 限流。
operationId: refreshToken
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RefreshRequest"
example:
refresh_token: eyJhbGciOiJIUzI1NiJ9...
responses:
"200":
description: 与登录相同的 LoginData
content:
application/json:
schema:
$ref: "#/components/schemas/LoginEnvelope"
/v1/auth/logout:
post:
tags: [auth]
summary: 退出当前设备
description: 吊销该设备的 access/refresh,并踢掉同 device_id 的 TCP 连接。
operationId: logout
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/users/me:
get:
tags: [users]
summary: 当前用户资料
operationId: getMe
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
example:
code: "0"
msg: ok
data:
uid: 1940000000000000000
spark_id: alice_ok
nickname: test01
avatar: perm/avatar/1940000000000000000/20260917/1940000000000000001.png
qrcode: "-NDveu-9Q"
birthday: ""
gender: 0
status: 1
last_login_time: 1726550000000
last_active_time: 1726550000000
create_time: 1726550000000
update_time: 1726550000000
patch:
tags: [users]
summary: 修改资料
description: 可改 spark_id、nickname、avatar、gender(0/1/2)、birthday(YYYY-MM-DD)。未出现的字段不改。
operationId: patchMe
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PatchMeRequest"
example:
nickname: Ada
gender: 2
birthday: "1994-05-01"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/friends/lookup:
get:
tags: [friends]
summary: 按邮箱 / Spark账号 / 二维码查找用户
description: |
查询参数 `email`、`spark_id`、`qrcode`、`uid` 四选一。
二维码为 shortid 个人扫描票据,不含 uid。对方已拉黑当前用户时返回 40401。
operationId: lookupFriend
parameters:
- in: query
name: email
schema: { type: string, format: email }
- in: query
name: spark_id
schema: { type: string }
- in: query
name: qrcode
schema: { type: string, example: "-NDveu-9Q" }
- in: query
name: uid
schema: { type: integer, format: int64 }
responses:
"200":
description: 统一 envelope,data 为好友卡片(含 relation:0无 1好友 2已拉黑)
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/friends/requests:
get:
tags: [friends]
summary: 收到的待处理好友申请
operationId: listFriendRequests
parameters:
- in: query
name: limit
schema: { type: integer, default: 20, maximum: 100 }
responses:
"200":
description: data.items
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
post:
tags: [friends]
summary: 发起好友申请
description: |
通过扫描二维码、搜索邮箱或 spark_id 发起。可填申请理由与备注。
同一对用户只保留一条申请,重复发起覆盖理由/备注,不新增行。
若对方已有待处理申请指向自己,则自动成为双向好友并写入一条系统消息。
不支持单向好友。
operationId: applyFriend
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/FriendApplyRequest"
example:
email: test02@spark.com
reason: 我是同事
remark: 同事
responses:
"200":
description: data.status 为 pending 或 accepted
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/friends:
get:
tags: [friends]
summary: 好友列表
operationId: listFriends
parameters:
- in: query
name: limit
schema: { type: integer, default: 20, maximum: 100 }
responses:
"200":
description: data.items
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
post:
tags: [friends]
summary: 同意好友申请
description: 成为双向好友后自动在单聊中插入一条 `kind=friend.became` 系统消息并入队 deliver。
operationId: acceptFriend
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/FriendAcceptRequest"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/friends/{uid}:
get:
tags: [friends]
summary: 查看好友资料
operationId: getFriend
parameters:
- $ref: "#/components/parameters/FriendUID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
delete:
tags: [friends]
summary: 删除好友
description: 解除双向关系,双方都不再是好友。
operationId: deleteFriend
parameters:
- $ref: "#/components/parameters/FriendUID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/friends/{uid}/remark:
put:
tags: [friends]
summary: 设置好友备注
operationId: setFriendRemark
parameters:
- $ref: "#/components/parameters/FriendUID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/FriendRemarkRequest"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/friends/{uid}/block:
put:
tags: [friends]
summary: 拉黑
description: 单向拉黑并解除好友关系。被拉黑一方再申请时视为用户不存在。
operationId: blockFriend
parameters:
- $ref: "#/components/parameters/FriendUID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
delete:
tags: [friends]
summary: 取消拉黑
operationId: unblockFriend
parameters:
- $ref: "#/components/parameters/FriendUID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/friends/{uid}/reports:
post:
tags: [friends]
summary: 投诉好友
operationId: reportFriend
parameters:
- $ref: "#/components/parameters/FriendUID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/FriendReportRequest"
example:
reason: 1
detail: spam
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/groups:
get:
tags: [groups]
summary: 我加入的群
operationId: listGroups
parameters:
- in: query
name: limit
schema: { type: integer, default: 20, maximum: 100 }
responses:
"200":
description: data.items,id 为自增群号,conversation_id 为 Snowflake 会话 id
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
post:
tags: [groups]
summary: 创建群
description: |
`id` 为表内自增群号。发消息、同步使用返回的 `conversation_id`(Snowflake)。
只能拉好友入群。群主无法直接退群,需先转让。
建群成功后服务端按实际人数拼接成员已有头像(注册默认或自定义),最多 9 人;两人就是并排两格,不会凑九宫格。
成员头像拉不到时用字母占位图,整张拼图失败则改用群名默认头像,`avatar` 不会为空。
写入 `perm/group/{群号}/`。之后可用 `purpose=group_avatar` 直传自定义头像再 PATCH。
operationId: createGroup
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateGroupRequest"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/groups/{id}:
get:
tags: [groups]
summary: 群资料
operationId: getGroup
parameters:
- $ref: "#/components/parameters/GroupID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
patch:
tags: [groups]
summary: 修改群名称 / 头像 / 全员禁言
operationId: updateGroup
parameters:
- $ref: "#/components/parameters/GroupID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateGroupRequest"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
delete:
tags: [groups]
summary: 解散群(仅群主)
operationId: dissolveGroup
parameters:
- $ref: "#/components/parameters/GroupID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/groups/{id}/members:
get:
tags: [groups]
summary: 群成员
operationId: listGroupMembers
parameters:
- $ref: "#/components/parameters/GroupID"
- in: query
name: limit
schema: { type: integer, default: 200, maximum: 200 }
responses:
"200":
description: data.items
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
post:
tags: [groups]
summary: 邀请好友入群
operationId: inviteGroupMembers
parameters:
- $ref: "#/components/parameters/GroupID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/InviteGroupMembersRequest"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/groups/{id}/members/{uid}:
patch:
tags: [groups]
summary: 改成员角色 / 禁言 / 群昵称
operationId: updateGroupMember
parameters:
- $ref: "#/components/parameters/GroupID"
- $ref: "#/components/parameters/FriendUID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateGroupMemberRequest"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
delete:
tags: [groups]
summary: 踢人,或 uid 为自己时退群
operationId: removeGroupMember
parameters:
- $ref: "#/components/parameters/GroupID"
- $ref: "#/components/parameters/FriendUID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/groups/{id}/transfer:
post:
tags: [groups]
summary: 转让群主
operationId: transferGroup
parameters:
- $ref: "#/components/parameters/GroupID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/TransferGroupRequest"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/files:
post:
tags: [files]
summary: 签发对象存储直传凭证
description: |
客户端只传 `purpose` / `mime` / `size`,服务端生成 object_key 并签发短时 Presigned PUT。
文件直传 RustFS,不经过 Gin。
`avatar` 写入 `perm/avatar/{uid}/…`(不过期);`group_avatar` 写入 `perm/group/{群号}/…`(需 `group_id`,群主/管理员);
聊天媒体写入 `chat/{yyyyMMdd}/{uid}/…`(桶生命周期过期)。
客户端 PUT 时必须带返回的 `headers`(至少 `Content-Type`)。消息与头像只存 `object_key`。
operationId: createUploadCredential
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUploadRequest"
example:
purpose: chat_image
mime: image/jpeg
size: 245760
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
example:
code: "0"
msg: ok
data:
object_key: chat/20260917/1/2.jpg
upload_url: http://47.236.66.9:9000/spark/chat/20260917/1/2.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256
method: PUT
headers:
Content-Type: image/jpeg
expires_in: 900
/v1/files/downloads:
post:
tags: [files]
summary: 签发对象存储下载凭证
description: 已登录用户用 object_key 换取短时 Presigned GET。key 必须是 `perm/` 或 `chat/` 前缀。
operationId: createDownloadCredential
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateDownloadRequest"
example:
object_key: chat/20260917/1/2.jpg
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/favorites:
get:
tags: [favorites]
summary: 收藏列表
operationId: listFavorites
parameters:
- in: query
name: limit
schema:
type: integer
default: 20
maximum: 100
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
post:
tags: [favorites]
summary: 收藏一条消息
description: |
会话成员可将消息收入收藏。图片/语音/视频/文件会 CopyObject 到 `perm/fav/{uid}/…`。
源对象已从 `chat/` 过期删除则失败(`code=40402`),不提供本地补传。
同一 `msg_id` 重复收藏返回已有记录。撤回不影响已收藏快照。
operationId: createFavorite
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateFavoriteRequest"
example:
msg_id: 1
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
/v1/favorites/{id}:
delete:
tags: [favorites]
summary: 取消收藏
operationId: deleteFavorite
parameters:
- $ref: "#/components/parameters/FavoriteID"
responses:
"200":
description: 统一 envelope
content:
application/json:
schema:
$ref: "#/components/schemas/Envelope"
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: Access JWT from /v1/auth/login. Same token is used for TCP AUTH.
schemas:
Envelope:
type: object
required: [code, msg, data]
properties:
code:
type: string
description: 业务码,成功为 "0"
example: "0"
msg:
type: string
example: ok
data:
type: object
additionalProperties: true
SendEmailCodeRequest:
type: object
required: [email]
properties:
email:
type: string
format: email
LoginRequest:
type: object
required: [email, verify_code, device_id]
properties:
email:
type: string
format: email
verify_code:
type: string
description: 邮箱验证码。测试账号 test01@spark.com~test10@spark.com 可任意填写。
device_id:
type: integer
format: int64
minimum: 1
device_type:
type: string
enum: [ios, android, harmony, windows, macos, web]
platform:
type: string
description: device_type 的兼容字段
enum: [ios, android, harmony, windows, macos, web]
device_name:
type: string
maxLength: 128
LoginData:
type: object
required: [access_token, refresh_token, expires_in, refresh_expires_in, user_id, device_id, spark_id]
properties:
access_token:
type: string
refresh_token:
type: string
expires_in:
type: integer
format: int64
description: access TTL in seconds (default 604800 = 7 days)
example: 604800
refresh_expires_in:
type: integer
format: int64
description: refresh TTL in seconds (default 2592000 = 30 days)
example: 2592000
user_id:
type: integer
format: int64
description: Snowflake user id
device_id:
type: integer
format: int64
spark_id:
type: string
description: Public handle, unique and user-changeable
RefreshRequest:
type: object
required: [refresh_token]
properties:
refresh_token:
type: string
PatchMeRequest:
type: object
properties:
spark_id:
type: string
minLength: 6
maxLength: 32
pattern: "^[a-zA-Z][a-zA-Z0-9_]{5,31}$"
nickname:
type: string
minLength: 1
maxLength: 64
avatar:
type: string
maxLength: 512
gender:
type: integer
enum: [0, 1, 2]
birthday:
type: string
description: YYYY-MM-DD;空字符串表示清除
example: "1994-05-01"
FriendApplyRequest:
type: object
properties:
uid:
type: integer
format: int64
email:
type: string
format: email
spark_id:
type: string
qrcode:
type: string
description: 个人二维码扫描票据(shortid),不含 uid
reason:
type: string
maxLength: 128
remark:
type: string
maxLength: 64
FriendAcceptRequest:
type: object
required: [request_id]
properties:
request_id:
type: integer
format: int64
remark:
type: string
maxLength: 64
FriendRemarkRequest:
type: object
properties:
remark:
type: string
maxLength: 64
FriendReportRequest:
type: object
required: [reason]
properties:
reason:
type: integer
enum: [1, 2, 3, 4]
description: 1=垃圾 2=骚扰 3=不实身份 4=其他
detail:
type: string
maxLength: 512
CreateUploadRequest:
type: object
required: [purpose, mime, size]
properties:
purpose:
type: string
enum: [avatar, group_avatar, chat_image, chat_voice, chat_video, chat_gif, chat_file]
mime:
type: string
example: image/jpeg
size:
type: integer
format: int64
minimum: 1
group_id:
type: integer
format: int64
minimum: 1
description: purpose=group_avatar 时必填,为自增群号
CreateDownloadRequest:
type: object
required: [object_key]
properties:
object_key:
type: string
maxLength: 512
CreateFavoriteRequest:
type: object
required: [msg_id]
properties:
msg_id:
type: integer
format: int64
minimum: 1
CreateGroupRequest:
type: object
required: [name, member_uids]
properties:
name:
type: string
minLength: 1
maxLength: 32
member_uids:
type: array
minItems: 1
maxItems: 199
items:
type: integer
format: int64
UpdateGroupRequest:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 32
avatar:
type: string
muted_all:
type: boolean
InviteGroupMembersRequest:
type: object
required: [uids]
properties:
uids:
type: array
minItems: 1
items:
type: integer
format: int64
UpdateGroupMemberRequest:
type: object
properties:
role:
type: integer
enum: [2, 3]
description: 2=管理员 3=普通成员;群主只能通过转让变更
speak_muted:
type: boolean
nickname:
type: string
maxLength: 32
TransferGroupRequest:
type: object
required: [uid]
properties:
uid:
type: integer
format: int64
LoginEnvelope:
type: object
required: [code, msg, data]
properties:
code:
type: string
msg:
type: string
data:
$ref: "#/components/schemas/LoginData"
AuthData:
type: object
properties:
user_id:
type: integer
format: int64
device_id:
type: integer
format: int64
MsgIDData:
type: object
properties:
msg_id:
type: integer
format: int64
headers:
X-Request-ID:
schema:
type: string
X-Trace-ID:
schema:
type: string
X-Device-ID:
schema:
type: string
description: Optional. Must match JWT did when present.
X-App-Version:
schema:
type: string
Accept-Language:
schema:
type: string
enum: [zh-CN, en, zh-TW]
example: zh-CN
description: 用户语言。也可用 X-Language。缺省 zh-CN。
X-Language:
schema:
type: string
enum: [zh-CN, en, zh-TW]
description: 覆盖 Accept-Language 的简洁语言标签。
X-Real-IP:
schema:
type: string
description: Nginx PROXY / SNI 写入的客户端真实 IP,进入 reqctx.RealIP。
parameters:
Authorization:
in: header
name: Authorization
required: true
schema:
type: string
description: "Bearer <jwt>"
X-Device-ID:
in: header
name: X-Device-ID
required: false
schema:
type: string
X-App-Version:
in: header
name: X-App-Version
required: false
schema:
type: string
Accept-Language:
in: header
name: Accept-Language
required: false
schema:
type: string
enum: [zh-CN, en, zh-TW]
description: 用户语言。缺省 zh-CN。
X-Language:
in: header
name: X-Language
required: false
schema:
type: string
enum: [zh-CN, en, zh-TW]
description: 覆盖 Accept-Language。
FriendUID:
in: path
name: uid
required: true
schema:
type: integer
format: int64
description: 对方 Snowflake uid。
FavoriteID:
in: path
name: id
required: true
schema:
type: integer
format: int64
description: 收藏 Snowflake id。
GroupID:
in: path
name: id
required: true
schema:
type: integer
format: int64
description: 自增群号(不是 conversation_id)。