这是 GeekApk Project 后端的完整文档,包含:
额外定义:
- 通知/Timeline 的 定义
- WebSocket API
- WebHooks 支持
- 身份验证 模式
API/数据结构:
- Postgres 表结构、限制和描述 文档
- JSON RESTFul API 对象 文档
- GeekApk RESTFul API 文档
- 使用 PostgreSQL 语言编写的 database migration 程序
- Diesel Rust Queryable, Insertable 数据结构定义
- 应该尽可能符合 GitHub Styled Markdown 语法规范,使用合适的中文文体并合理使用 斜体 粗体
代码块
链接 - 粗体 在强调对象描述时使用、斜体 在引用对象时使用、
代码块
在引用代码时使用、如果有必要,可以给 资源 添加链接 - 不应该有不正确的 缩进、空格、大小写、全半角符号,中文字符(非全角标点)和 数字/英文字符 间必须添加空格
在合适的地方也可以使用 Markdown 引用 添加额外 注意事项
- 数据库字段的英文单词的 单复数 问题: 数据库表 使用 复数,其他 则使用 单数
- 有可能为字段添加所存储数据模式描述的,则添加描述,如:
install_url
、icon_url
、parent_category
- 记录 创建时间 和 更新时间 的字段使用命名
created_at
和updated_at
- RDBMS 对象引用字段使用 所引用对象单数名称 为名称,如
user
、app
- PostgreSQL 中,非类型声明的关键字 全大写,类型声明使用 PascalCased,标识符 全小写
- Postgres 中,可能为
Null
的字段在 Rust 中表示为Option<T>
- PostgreSQL 中,仅 描述数据结构,不要设置除
NOT Null
外的 约束 - 关于排行所用自动生成字段的问题,必须加
_num
- 仔细检查
database migration up/down、rust struct
中字段和表的名称是否对应 - 在数据结构中合理的增加 限制,如 版本名长度 限制
其实这个文档是很可爱的 (´・ω・`)
GeekApk 里,通知 作为一种对 用户 的提醒而存在,一般在 动作执行后 直接保存等待用户阅读,GeekApk 中有这些通知:
- 用户 的 评论 被 回复 的通知
- 用户 被
@
提到 的通知 - 用户 被 用户 跟随 的通知
- 用户 的 评论 被 星标 的通知
类似 GitHub,GeekApk 也会记录每个 用户 的公开活动并允许所有人自由查询,这个特性被称为 Timeline(时间线),GeekApk 中有这些时间线记录:
- 用户 Follow 了某个 用户
- 用户 Star 了某个 评论
- 用户 创建了 某个 评论
- 用户 更新了 某个 评论
- 用户 发布了 某个 应用
- 用户 发布了 某个 应用 的 更新
- 用户 删除了 某个 应用
- 用户 Star 了某个 应用
WebSocket 为 GeekApk 提供了即时通知推送的特性,除此之外还有查询 WebSocket 在线 和发送 即时消息 的能力
GeekApk 服务会把 WebSocket 服务开在 2333 端口上,要建立连接 URL 使用以下格式:
wss://api.geekapk.org:2333/:uid/:passhash
由于推送和送信服务只对 已登录用户 有意义,WebSocket 必须 先验证身份才可以连接
其实这个是可以有状态机描述的,我不想写,这文档也很明了了
o
以查询 WebSocket 在线人数,服务器会返回一个 短整数(SmallInt) 的字符串表示如12
、322
、0
o?
+ 以分号','
切分的 UID 短整数 列表以查询目标用户是否在线,服务器返回以'*'
打头的0
和1
组成的在线状态字符串,其长度等于 UID 列表 的长度,与 UID 列表对应位置的 UID 对应,如 发送o?12,32,43,32,43
接收*01010
uid:message
以向 UID 发送一条消息,若不在线即收到发送错误
- 可能是空的字符串,代表 通知 有更新
- 可能是一个值等于
ERROR
的字符,代表发送操作出现错误 - 可能是一个数字字符串,代表
o
的查询结果 - 可能是一个以
'*'
打头的字符串,代表o?
的查询结果 - 可能是一个包含
':'
的字符串,在':'
前的部分为发送者 UID,后面的部分为 消息
GeekApk 可以与 第三方服务 进行 集成,服务端使用的支持方式就是 WebHooks
WebHooks 可以让 GeekApk 服务器在进行某种操作后 通知 外部服务进行相应的处理
GeekApk 目前支持 3 种 WebHooks:
- replyToMessage 在回复指定 评论 时触发
- commentApp 在回复指定 应用 时触发
- newUser 在添加一个 用户 时触发
GeekApk 服务器内部使用 环境变量 存储 WebHooks 设置,同时,要应用新 WebHooks 设置需要 重启服务器
WEBHOOKS='replyToMessage:2333:https://bar.org/bot;commentApp:23:https://geekbot.com/webhook;newUser:https://webhooks.org/bot;'
触发时 GeekApk 服务器使用 POST
为 HTTP 方法,相应 对象 的 ID 为 POST body 请求目标地址
如果请求失败,错误记录只会被打印在服务程序的 标准错误输出 里
GeekApk 使用 基于角色 的权限系统,验证需要的令牌保存在 cookie 里
GeekApk 有以下 3 种角色:
- 权限汪 🐶(确信)
- 用户
- 未登录用户
无论是 权限汪、用户 还是 未登录用户 实体都可以有多个
权限汪不一定需要有一个 GeekApk 账户,实际上,权限汪只需要服务器的 管理令牌 就可以验证自己的身份
这也意味着权限汪其实只代表了 GeekApk 管理人员 比 普通用户 多 的权限,但它没有普通用户所拥有的权限 233
- 权限汪可以创建/删除 用户
- 权限汪可以修改 用户 的 分发密码
- 权限汪可以停用/激活 用户
- 权限汪可以创建/修改/删除 分类
- 权限汪可以删除 评论
- 权限汪可以删除 应用
权限汪需要知道服务器根据启动时 DOGETOK
环境变量设置的密码并在请求相应 管理 API 时作为 cookie 参数 doge_token
填写
- 用户不能创建 用户
- 用户不能创建 分类
- 用户可以 创建 未禁止创建的 实体 和 修改/删除 自己所创建的 实体 或 notification 记录
- 用户可以 登录 WebSocket 平台
用户需要使用 分发密码 创建一个自己的 密码(内部表示为 passhash
)
在创建之后,用户也可以使用 分发密码(内部表示为 metapass
)重置自己的密码
WebSocket 验证方式参见上文 WebSocket API,请求需要 验证身份 的 API 时,必须携带 geekapk_uid
和 geekapk_passhash
两个 cookie 来验证自己的身份,服务器 不会猜测 你需要使用的用户身份
除了 只读访问 和 登录 WebSocket 平台 外没有其它限制
中文名 | 实体名 | 表名 | ID 名 | 描述 |
---|---|---|---|---|
用户 | user | users | uid | GeekApk 用户帐号 |
分类 | category | categories | tid | GeekApk 应用分类 |
应用 | app | apps | aid | GeekApk 应用 |
评论 | comment | comments | cid | GeekApk 评论 |
对象的辅助表:
中文名 | 实体名 | 表名 | 所属对象 | 描述 |
---|---|---|---|---|
跟随 | follow | 用户 | 用户跟随 | |
密码 | _security | 用户 | 用户密码 | |
更新 | update | updates | 应用 | 应用更新 |
星标 | stars | 应用 | 应用星标 | |
评论星标 | comment_stars | 评论 | 评论星标 | |
时间线 | timeline | timelines | 用户 | 时间线记录 |
通知 | notification | notifications | 用户 | 通知条目 |
用户 对象关系:
- 只能有一个 密码
- 可以有很多个 应用
- 可以有很多条 评论
- 可以有很多条 跟随
- 可以有很多个 星标
- 可以有很多个 评论星标
- 可以有很多条 时间线
- 可以有很多条 通知
分类 对象关系:
- 只能有一个 父 分类
- 可以包含很多个 应用
应用 对象关系:
- 只能有一个创建人 用户
- 只能有一个归属 分类
- 可以有很多条 评论
- 可以有很多条 更新
- 可以有很多条 星标
评论 对象关系:
- 只能有一个创建人 用户
- 只能有一个评论目标 应用
- 只能有一个回复目标 评论
- 可以有很多个 评论星标
排行设计:
- 用户 可以按 创建时间、上线时间、跟随者人数 排行
- 应用 可以按 创建时间、更新时间、星标数、评论数、体积 徘行
- 评论 可以按 创建时间、更新时间、评论星标数、回复数 排行
分页设计: 时间线、评论、用户、应用 可以设置返回的 最大条数
检索设计:
- 用户 可以用 简单名、用户名、别名、GitHub、自述、开发者自述 检索
- 应用 可以用 应用名、包名、描述 检索
- 评论 可以用 内容 检索
考虑到清晰度的原因,设计上不会添加 rate limit,但实践中有可能在文档规定外添加一定的限制
SmallSerial
、Serial
本质上不是一个类型,这里为了方便将它作为一个类型,希望大家能理解原意
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
id | SmallSerial |
PRIMARY KEY |
|
simple_name | VarChar |
非空、长度小于 20 个字符、只能包含 [A-z] 、[a-z] 、[0-9] 、_ |
用户的机器可读名称 |
avatar_url | VarChar |
长度小于 500 字符 | 用户的头像 URL |
user_name | VarChar |
非空、长度小于 100 字符 | 用户名 |
alias | VarChar |
长度小于 50 字符 | 用户别名 |
github | VarChar |
长度小于 50 字符 | GitHub 用户名 |
bio | VarChar |
非空、长度小于 500 字符 | DEFAULT '' 用户自我介绍 |
dev_bio | VarChar |
长度小于 500 字符 | 作为开发者的自我介绍 |
created_at | TimeStamp |
非空 | DEFAULT now() 用户创建时间 |
online_at | TimeStamp |
非空 | DEFAULT now() 用户最近上线时间,由用户手动更新 |
followers_num | SmallInt |
非空 | DEFAULT 0 用户的跟随者数目 |
enabled | Boolean |
非空 | DEFAULT true 用户是否启用 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
id | SmallSerial |
PRIMARY KEY |
|
category_name | VarChar |
非空 | 分类名,因为只有内部人员操作不加限制 |
parent_category | SmallInt |
父 分类 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
id | SmallSerial |
PRIMARY KEY |
|
author_user | SmallInt |
非空 | 创建者 UID |
category | SmallInt |
非空 | 归属 TID |
package_name | VarChar |
长度小于 60 字符 | 包名 |
app_name | VarChar |
非空、长度小于 60 字符 | 应用名 |
alias | VarChar |
长度小于 60 字符 | 别名 |
icon_url | VarChar |
长度小于 500 字符 | 图标 URL |
app_description | VarChar |
非空、长度小于 10000 字符 | DEFAULT '' 应用描述 |
visualizer | VarChar |
长度小于 20 字符 | 应用模型视图 |
button_text | VarChar |
长度小于 60 字符 | 安装卸载按钮 文本覆盖 |
special | VarChar |
长度小于 12 字符 | 特殊标识 |
previews | VarChar |
长度小于 4000 字符 | 以 ';' 切分的预览图 URL |
app_permissions | VarChar |
长度小于 10000 字符 | 以 '\n' 切分的权限列表 |
size | Integer |
非空 | DEFAULT 0 应用安装包以 百字节 计体积 |
created_at | TimeStamp |
非空 | DEFAULT now() 创建时间 |
updated_at | TimeStamp |
非空 | DEFAULT now() 更新时间 |
stars_num | SmallInt |
非空 | DEFAULT 0 星标数 |
comments_num | Integer |
非空 | DEFAULT 0 评论数 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
id | Serial |
PRIMARY KEY |
|
author_user | SmallInt |
非空 | 创建人 UID |
app | SmallInt |
非空 | 评论 AID |
reply_comment | Integer |
回复 CID | |
content | VarChar |
非空、长度小于 7000 字符 | 评论内容 |
stars_num | SmallInt |
非空 | DEFAULT 0 星标数 |
replies_num | Integer |
非空 | DEFAULT 0 回复数 |
created_at | TimeStamp |
非空 | DEFAULT now() 创建时间 |
updated_at | TimeStamp |
修改时间 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
user | SmallInt |
非空 | 跟随者 UID |
followed_user | SmallInt |
非空 | 被跟随者 UID |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
user | SmallInt |
PRIMARY KEY 目标用户 |
|
metapass | VarChar |
非空 | 分发密码 |
passhash | VarChar |
SHA-256 密码取样 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
app | SmallInt |
非空 | 目标 AID |
version_name | VarChar |
非空,长度小于 40 字符 | 版本名 |
reversion | SmallInt |
非空 | 修订号 |
install_url | VarChar |
非空,长度小于 500 字符 | 安装 GFC |
updates | VarChar |
非空,长度小于 6000 字符 | 更新内容 |
api_min | SmallInt |
最低 SDK 版本 | |
api_target | SmallInt |
目标 SDK 版本 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
user | SmallInt |
非空 | 操作 用户 |
app | SmallInt |
非空 | 目标 应用 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
user | SmallInt |
非空 | 操作 用户 |
comment | Integer |
非空 | 目标 评论 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
user | SmallInt |
非空 | 用户 |
created_at | TimeStamp |
非空 | DEFAULT now() 创建时间 |
line_type | SmallInt |
非空 | 时间线类型 |
line_data | Integer |
非空 | 时间线数据 |
字段名 | 类型 | 限制 | 注 |
---|---|---|---|
user | SmallInt |
非空 | 用户 |
created_at | TimeStamp |
非空 | DEFAULT now() 创建时间 |
notification_type | SmallInt |
非空 | 通知类型 |
notification_data | Integer |
非空 | 通知数据 |
enabled | Boolean |
非空 | DEFAULT false 已经阅读 |
CREATE TABLE users(
id SmallSerial PRIMARY KEY,
simple_name VarChar NOT Null,
avatar_url VarChar,
user_name VarChar NOT Null,
alias VarChar,
github VarChar,
bio VarChar NOT Null DEFAULT '',
dev_bio VarChar,
created_at TimeStamp NOT Null DEFAULT now(),
online_at TimeStamp NOT Null DEFAULT now(),
followers_num SmallInt NOT Null DEFAULT 0,
enabled Boolean NOT Null DEFAULT true
)
DROP TABLE users
CREATE TABLE categories(
id SmallSerial PRIMARY KEY,
category_name VarChar NOT Null,
parent_category SmallInt
)
DROP TABLE categories
CREATE TABLE apps(
id SmallSerial PRIMARY KEY,
author_user SmallInt NOT Null,
category SmallInt NOT Null,
package_name VarChar,
app_name VarChar NOT Null,
alias VarChar,
icon_url VarChar,
app_description VarChar NOT Null DEFAULT '',
visualizer VarChar,
button_text VarChar,
special VarChar,
previews VarChar,
app_permissions VarChar,
size Integer NOT Null DEFAULT 0,
created_at TimeStamp NOT Null DEFAULT now(),
updated_at TimeStamp NOT Null DEFAULT now(),
stars_num SmallInt NOT Null DEFAULT 0,
comments_num Integer NOT Null DEFAULT 0
)
DROP TABLE apps
CREATE TABLE comments(
id Serial PRIMARY KEY,
author_user SmallInt NOT Null,
app SmallInt NOT Null,
reply_comment Integer,
content VarChar NOT Null,
stars_num SmallInt NOT Null DEFAULT 0,
replies_num Integer NOT Null DEFAULT 0,
created_at TimeStamp NOT Null DEFAULT now()
updated_at TimeStamp
)
DROP TABLE comments
CREATE TABLE follow(
user SmallInt NOT Null,
followed_user SmallInt NOT Null
)
DROP TABLE follow
CREATE TABLE _security(
user SmallInt PRIMARY KEY,
metapass VarChar NOT Null,
passhash VarChar
)
DROP TABLE _security
CREATE TABLE updates(
app SmallInt NOT Null,
version_name VarChar NOT Null,
reversion SmallInt NOT Null,
install_url VarChar NOT Null,
updates VarChar NOT Null,
api_min SmallInt,
api_target SmallInt
)
DROP TABLE updates
CREATE TABLE stars(
user SmallInt NOT Null,
app SmallInt NOT Null
)
DROP TABLE stars
CREATE TABLE comment_stars(
user SmallInt NOT Null,
comment Integer NOT Null
)
DROP TABLE comment_stars
CREATE TABLE timelines(
user SmallInt NOT Null,
created_at TimeStamp NOT Null DEFAULT now(),
line_type SmallInt NOT Null,
line_data Integer NOT Null
)
DROP TABLE timelines
CREATE TABLE notifications(
user SmallInt NOT Null,
created_at TimeStamp NOT Null DEFAULT now(),
notification_type SmallInt NOT Null,
notification_data Integer NOT Null,
enabled Boolean NOT Null DEFAULT false
)
DROP TABLE notifications
#[derive(Queryable)]
pub struct User {
id: i16,
simple_name: String,
avatar_url: Option<String>,
user_name: String,
alias: Option<String>,
github: Option<String>,
bio: String,
dev_bio: Option<String>,
created_at: SystemTime,
online_at SystemTime,
followers_num: i16,
enabled: bool
}
#[derive(Insertable)]
#[table_name="users"]
pub struct NewUser<'a> {
simple_name: String,
avatar_url: Option<String>,
user_name: String,
alias: Option<String>,
github: Option<String>,
bio: String,
dev_bio: Option<String>
}
#[derive(Queryable)]
pub struct Category {
id: i16,
category_name: String,
parent_category: Option<i16>
}
#[derive(Insertable)]
#[table_name="categories"]
pub struct NewCategory<'a> {
category_name: String,
parent_category: Option<i16>
}
#[derive(Queryable)]
pub struct App {
id: i16,
author_user: i16,
category: i16,
package_name: Option<String>,
app_name: String,
alias: Option<String>,
icon_url: Option<String>,
app_description: String,
visualizer: Option<String>,
button_text: Option<String>,
special: Option<String>,
previews: Option<String>,
app_permissions: Option<String>,
size: i32,
created_at: SystemTime,
updated_at: SystemTime,
stars_num: i16,
comments_num: i32
}
#[derive(Insertable)]
#[table_name="apps"]
pub struct NewApp<'a> {
author_user: i16,
category: i16,
package_name: Option<String>,
app_name: String,
alias: Option<String>,
icon_url: Option<String>,
app_description: String,
visualizer: Option<String>,
button_text: Option<String>,
special: Option<String>,
previews: Option<String>,
app_permissions: Option<String>,
size: i32
}
#[derive(Queryable)]
pub struct Comment {
id: i32,
author_user: i16,
app: i16,
reply_comment: Option<i32>,
content: String,
stars_num: i16,
replies_num: i32,
created_at: SystemTime,
updated_at: Option<SystemTime>
}
#[derive(Insertable)]
#[table_name="comments"]
pub struct NewComment<'a> {
author_user: i16,
app: i16,
reply_comment: Option<i32>,
content: String
}
#[derive(Queryable)]
#[table_name="follow"]
pub struct Follow {
user: i16,
followed_user: i16
}
#[derive(Insertable)]
#[table_name="follow"]
pub struct NewFollow<'a> {
user: i16,
followed_user: i16
}
#[derive(Queryable)]
#[table_name="_security"]
pub struct Security {
user: i16,
metapass: String,
passhash: Option<String>
}
#[derive(Insertable)]
#[table_name="_security"]
pub struct NewSecurity<'a> {
user: i16,
metapass: String,
passhash: Option<String>
}
#[derive(Queryable)]
pub struct Update {
app: i16,
version: String,
reversion: i16,
install_url: String,
updates: String,
api_min: Option<i16>,
api_target: Option<i16>
}
#[derive(Insertable)]
#[table_name="updates"]
pub struct NewUpdate<'a> {
app: i16,
version: String,
reversion: i16,
install_url: String,
updates: String,
api_min: Option<i16>,
api_target: Option<i16>
}
#[derive(Queryable)]
pub struct Star {
user: i16,
app: i16
}
#[derive(Insertable)]
#[table_name="stars"]
pub struct NewStar<'a> {
user: i16,
app: i16
}
#[derive(Queryable)]
pub struct CommentStar {
user: i16,
comment: i32
}
#[derive(Insertable)]
#[table_name="comment_stars"]
pub struct NewCommentStar<'a> {
user: i16,
comment: i32
}
#[derive(Queryable)]
pub struct Timeline {
user: i16,
created_at: SystemTime,
line_type: i16,
line_data: i32
}
#[derive(Insertable)]
#[table_name="timelines"]
pub struct NewTimeline<'a> {
user: i16,
line_type: i16,
line_data: i32
}
#[derive(Queryable)]
pub struct Notification {
user: i16,
created_at: SystemTime,
notification_type: i16,
notification_data: i32,
enabled: bool
}
#[derive(Insertable)]
#[table_name="notifications"]
pub struct NewNotification<'a> {
user: i16,
notification_type: i16,
notification_data: i32,
}
如果请求使用数据的长度过长,返回 413 Payload Too Large
如果验证失败,返回 401 Unauthorized
如果找不到资源,返回 404 Not Found
如果请求类型不合适,返回 415 Unsupported Media Type
如果内容解析失败,返回 400 Bad Request
额外访问 密码 表的内容
GET /
返回主页 web.html
GET /version
返回以 ':'
分割的 API 版本、程序版本
GET /ping
返回你的 IP 地址
以 metapass 为 body POST /validate-metapass/<uid>
获得验证是否通过(200/非 200)
以 passhash 为 body POST /validate/<uid>
获得验证是否通过(200/非 200)
以分发密码为 body,PUT /pass/<uid>
可以创建/更新用户密码
如果成功,返回 200 OK
如果验证失败,返回 401 Unauthorized
如果找不到用户,返回 404 Not Found
GET /webhooks
查询 WebHooks 配置
[
{
"type": "replyToMessage",
"data": 2333,
"url": "https://bar.org/bot"
}
]
以下 API 都需要 权限汪 访问权限
如果验证失败,返回 401 Unauthorized
POST /doge/useradd
body 包含
simple_name: string,
avatar_url: string / null,
user_name: string / null,
alias: string / null,
github: string,
bio: string(optional),
dev_bio: string / null
如果返回码为 201 Created
,body 就应该是以 ':'
切分的被创建的用户 UID 文本表示和 metapass
DELETE /doge/user/<uid>
如果成功删除,返回 410 Gone
如果找不到用户,返回 404 Not Found
PUT /doge/user/<uid>
如果成功,则返回 200 OK
和 Json
例如,
{
"uid": 213,
"enabled": true
}
如果找不到用户,返回 404 Not Found
以新 metapass 为 body PUT /doge/user/<uid>/metapass
如果找不到用户,返回 404 Not Found
如果成功,则返回 200 OK
和 Json
例如,
{
"uid": 233,
"old-metapass": "old",
"metapass": "new"
}
以分类名为 body POST /doge/category/<parent>
如果成功,返回 200 OK
和已创建 CID 文本表示
以新分类名为 body PUT /doge/category/<tid>
以新父分类为 body PUT /doge/category/<tid>/parent
如果成功,返回 200 OK
和 Json
例如,
{
"tid": 32,
"name": "实用工具",
"parent": 3
}
DELETE /doge/category/<tid>
如果成功,返回 410 Gone
DELETE /doge/comment/<cid>
如果有子评论,删除评论也会在应用 0 下以被删除所有者身份新建顶级评论 Replies Deleted from {aid} (reply to {reply_comment})
并将所有子评论的 reply_comment
字段修改为 该评论 ID
并且把 app
字段修改为 0,直接被删除的内容不会保留
DELETE /doge/comment/<cid>
如果添加 url 参数 recursive
则递归删除所有子评论
如果成功,返回 410 Gone
如果没找到评论,返回 404 Not Found
DELETE /doge/comment/<cid>
如果有评论,在应用 0 下以应用发布者身份创建顶级评论 Comments Deleted from {aid}
并将所有评论的 app
字段修改为 0,reply_comment
修改为评论的 cid
如果添加 url 参数 recursive
则递归删除所有评论
如果成功,返回 410 Gone
如果没找到评论,返回 404 Not Found
额外访问 跟随 表的内容
GET /user/<uid>
可以获取目标用户的 User JSON,如果使用 short
参数就不传输一些字段(简短 JSON)
GET /user/all
可以获得全站用户 UID JSON 列表,参数
max=num
可以设置最大返回条数s=ctime
可以设置以创建时间排行s=otime
可以设置以上线时间排行s=followers
可以设置以跟随人数徘行m=asc/dsc
以设置是asc
正序还是dsc
倒序,默认正序
以关键字为 body POST /user/search
以搜索用户,返回用户 UID JSON 列表,参数
mode=sname/name/alias/github/bio/dev_bio
以 简单名、用户名、别名、GitHub、自述、开发者自述 搜索max=num
可以设置最大返回条数s=ctime
可以设置以创建时间排行s=otime
可以设置以上线时间排行s=followers
可以设置以跟随人数徘行m=asc/dsc
以设置是asc
正序还是dsc
倒序,默认正序
GET /user/<uid>/followers
可以获取目标用户的跟随者 用户 UID JSON 列表,默认排行
GET /user/<uid>/following
可以获取目标用户的跟随 用户 UID JSON 列表,默认排行
GET /user/<uid>/follow
返回 follow 状态 true/false
PUT /user/<uid>/follow
改变 follow 状态,返回新状态 true/false
GET /user/<uid>/online
可以获取用户上线时间
GET /user/<uid>/apps
可以获取用户的应用 AID JSON 列表,以更新时间排行
GET /user/<uid>/comments
可以获取用户的评论 CID JSON 列表,以发布时间排行
GET /user/<uid>/stars
可以获得用户的星标应用 AID JSON 列表
GET /user/<uid>/cstars
可以获得用户的星标评论 CID JSON 列表
GET /user/<uid>/timeline
可以获得用户的时间线 JSON 对象列表,参数
max=num
设置最大返回条数
GET /user/<uid>/notifications
可以获得用户的通知 JSON 对象列表,需要验证
all
参数以返回已阅消息
以 User JSON 为 body PUT /user/<uid>
可以更新目标用户除 id, created_at, followers_num, enabled
外的信息
PUT /user/<uid>/online
可以更新上线时间为当前时间
DELETE /user/<uid>
可以删除自己,言论和应用不会删除
GET /category/all
获取所有分类 JSON 列表
GET /category/<tid>
获取这个分类的 JSON 对象
GET /category/<tid>/parent
获取这个分类的父分类
GET /category/<tid>/apps
获取这个分类的应用 AID JSON 列表,参数
max=num
条数限制m=asc/dsc
以设置是asc
正序还是dsc
倒序,默认正序s=ctime/updated/star/replies/size
以 创建时间、更新时间、星标数、评论数、体积 排序
以关键字为 body POST /category/<tid>/search
在分类中搜索应用,返回 AID JSON 列表,参数
max=num
条数限制s=name/pkg/desc
检索类型,应用名、包名、描述
额外访问 星标 表的内容
以包含 author_user, category, package_name(optional), app_name, alias(optional), icon_url(optional), app_description, visualizer(optional), button_text(optional), special(optional), previews(optional), app_permissions(optional), size
的 App JSON 为 body POST /app
创建应用,返回应用 AID
GET /app/all
获取所有应用 AID JSON 列表,按更新时间排序
GET /app/<aid>
获取 App JSON,可选 short
参数获取简版对象
GET /app/<aid>/stars
获取 star 的用户 UID JSON 列表
GET /app/<aid>/star
查询星标状态,返回 true/false
PUT /app/<aid>/stars
以星标/取消星标应用,返回新状态 true/false
GET /app/<aid>/comments
获取评论列表,参数
max=num
条数限制s=ctime/utime/stars/replies
创建时间、更新时间、评论星标数、回复数 排行
GET /app/<aid>/updates
获取更新 JSON 对象列表,以 reversion
排行
max=num
条数限制
以包含 version_name, reversion, install_url, updates, api_min(optional), api_target(optional)
的 Update JSON 为 body POST /app/<aid>/update
创建更新
以包含 reply_comment, content
的 comment JSON POST /app/<aid>/comment
创建评论,返回评论 CID
以 App JSON 为 body PUT /app/<aid>
更新应用的非 id, author_user, created_at, updated_at, stars_num, comments_num
字段
以关键字为 body POST /app/search
搜索应用,返回 AID JSON 列表,参数
max=num
条数限制s=name/pkg/desc
检索类型,应用名、包名、描述
DELETE /app/<aid>
以删除应用,评论将被迁移到特殊应用 0 的评论下
额外访问 评论星标 表的内容
GET /comment/all
获取创建时间排行的全站 CID JSON 列表
GET /comment/<cid>
获取评论 JSON 对象
以新内容为 body PUT /comment/<cid>
更新评论内容
GET /comment/<cid>/star
查询星标状态,返回 true/false
PUT /comment/<cid>/star
以星标/取消星标评论,返回新状态 true/false
GET /comment/<cid>/replies
获取回复评论的 CID JSON 列表
GET /comment/<cid>/stars
获取星标用户 UID JSON 列表
以关键字为 body POST /comment/search
搜索评论,返回 CID JSON 列表,参数
max=num
条数限制
DELETE /comment/<cid>
删除评论,子评论会被迁移
以 App JSON 为 body PUT /updates/<aid>/<reversion>
更新 version_name, install_url, updates, api_min, api_target
DELETE /updates/<aid>/<reversion>
以删除指定 reversion
GET /updates/<aid>
以获得 reversion 数目
GET /timeline
获取全站时间线 Timeline JSON 对象列表
max=num
限制条数
POST /notification/<uid>/<cid>
新建一个 @
PUT /notification/<uid>/<created>
更新 enabled
状态,返回新状态 true/false
DELETE /notification/<uid>/<created>
删除目标通知
字段名 | 类型 | 描述 |
---|---|---|
id | number | 用户 UID |
simple_name | string | 用户简名 |
avatar_url | string / null | 用户头像链接 |
name | string | 用户名 |
alias | string / null | 用户别名 |
github | string / null | github 名 |
bio | string | 介绍(可省略) |
dev_bio | string / null | 开发者介绍(可省略) |
created_at | number(datetime) | 创建时间 |
online_at | number(datetime) | 上线时间 |
followers_num | number | 跟随人数 |
enabled | boolean | 启用状态 |
{
"id": 3,
"simple_name": "rachel030219",
"avatar_url": "https://avatars1.githubusercontent.com/u/13704467?s=460&v=4",
"name": "Rachel",
"alias": null,
"github": "Rachel030219",
"bio": "Rachel 坏耶",
"dev_bio": "Code? Is that edible?",
"created_at": 1527689792253,
"online_at": 1527689792253,
"followers_num": 15,
"enabled": true
}
{
"id": 233,
"simple_name": "yuuta",
"avatar_url": "https://avatars0.githubusercontent.com/u/17158086?s=460&v=4",
"name": "Yuuta",
"alias": "Trumeet",
"github": "Trumeet",
"bio": "Trumeet 好耶",
"dev_bio": null,
"created_at": 1527689792353,
"online_at": 1527689795253,
"followers_num": 200,
"enabled": true
}
{
"id": 234,
"simple_name": "pandecheng",
"avatar_url": "https://avatars0.githubusercontent.com/u/26184272?s=460&v=4",
"name": "pandecheng",
"alias": null,
"github": "pandecheng36",
"bio": "",
"dev_bio": "女装大佬,图标包高产赛 **,日常修图改图",
"created_at": 1527689892353,
"online_at": 1527689995253,
"followers_num": 200,
"enabled": false
}
小潘日常被管理欺负
字段名 | 类型 | 描述 |
---|---|---|
id | number | 分类 TID |
name | string | 分类名 |
parent | number | 父分类 TID |
{
"id": 1,
"name": "应用",
"parent": null
}
{
"id": 2,
"name": "工具",
"parent": 1
}
{
"id": 3,
"name": "编辑器",
"parent": 2
}
字段名 | 类型 | 描述 |
---|---|---|
id | number | 应用 AID |
author | number | 所有者 UID |
category | number | 分类 TID |
package | string / null | 包名 |
name | string | 应用名 |
alias | string / null | 别名 |
icon_url | string / null | 图标链接 |
desc | string | 描述(可省略) |
visual | string / null | 展示器名(可省略) |
button | string / null | 按钮文本覆盖(可省略) |
special | string / null | 特殊文本 |
previews | string / null | 预览 url 文本(可省略) |
permissons | string / null | 权限(可省略) |
size | number | 安装包大小 |
created_at | number(datetime) | 创建时间 |
updated_at | number(datetime) | 更新时间 |
stars_num | number | 星标数目 |
comments_num | number | 评论数目 |
{
"id": 1,
"author": 2,
"category": 3,
"package": "com.drakeet.purewriter",
"name": "纯纯写作",
"alias": "Pure Writer",
"icon_url": ":coolapk",
"desc": ":apkpure",
"visual": null,
"button": null,
"special": "永不打折降价",
"previews": ":coolapk",
"permissions": ":coolapk",
"size": 23333,
"created_at": 0,
"updated_at": 0,
"stars_num": 500,
"comments_num": 100
}
{
"id": 3,
"author": 233,
"category": 7,
"package": "kh.android.dir",
"name": "Dir",
"alias": null,
"icon_url": ":coolapk",
"desc": ":apkpure",
"visual": null,
"button": "获取~/删除 QAQ/Getting...",
"special": null,
"previews": ":coolapk",
"permissions": ":coolapk",
"size": 23333,
"created_at": 0,
"updated_at": 0,
"stars_num": 500,
"comments_num": 100
}
{
"id": 5,
"author": 0,
"category": 12,
"package": "org.geekapk.virtual.news.android-pill",
"name": "Android Pill",
"alias": "药丸的 Android",
"icon_url": "https://example.org/favicon.ico",
"desc": "日常放送一点 :pill: 的 Android 资讯",
"visual": "news",
"button": null,
"special": null,
"previews": "",
"permissions": "",
"size": 0,
"created_at": 0,
"updated_at": 0,
"stars_num": 700,
"comments_num": 100
}
字段名 | 类型 | 描述 |
---|---|---|
id | number | 评论 CID |
author | number | 所有者 UID |
app | number | 所在 AID |
reply | number / null | 回复给 CID 或不是回复 |
content | string | 内容 |
stars_num | number | 星标数目 |
replies_num | number | 回复数目 |
created_at | number(datetime) | 创建时间 |
updated_at | number(datetime) / null | 更新时间或没有更新过 |
{
"id": 306,
"author": 233,
"app": 1,
"reply": null,
"content": "好耶(跑",
"stars_num": 0,
"replies_num": 0,
"created_at": 1527693014709,
"updated_at": null
}
{
"id": 500,
"author": 234,
"app": 5,
"reply": 451,
"content": "这个厉害了&em@doge/smile!&",
"stars_num": 4,
"replies_num": 0,
"created_at": 1527693014809,
"updated_at": null
}
{
"id": 62,
"author": 3,
"app": 3,
"reply": null,
"content": "&em@emoji/fish!&",
"stars_num": 0,
"replies_num": 0,
"created_at": 1527693113700,
"updated_at": 1527693113809
}
字段名 | 类型 | 描述 |
---|---|---|
app | number | 更新目标 AID |
ver | string | 版本名 |
rev | number | 修订号 |
install_url | string | 安装链接 |
updates | string | 更新内容 |
api_min | number / null | 最低兼容 Android API 版本 |
api_target | number / null | 目标 Android API 版本 |
{
"app": 1,
"ver": "3.0.0",
"rev": 14,
"install_url": "coolapk:com.drakeet.purewriter",
"updates": ":coolapk",
"api_min": 17,
"api_target": 24
}
字段名 | 类型 | 描述 |
---|---|---|
u | number | 用户 UID |
t | number | 时间线类型 |
d | number | 数据 |
c | number(datetime) | 创建日期 |
{
"u": 233,
"t": 8,
"d": 1,
"c": 1527693113809
}
字段名 | 类型 | 描述 |
---|---|---|
user | number | 用户 UID |
created_at | number(datetime) | 创建时间 |
type | number | 通知类型 |
data | number | 数据 |
enabled | boolean | 是否已阅 |
{
"user": 233,
"created_at": 1527693113809,
"type": 1,
"data": 542,
"enabled": false
}