Formatter
/api/v1

API 文档

一次 POST 请求就能处理一个文件。不需要密钥、账号或签名——地址加上请求体就是全部约定。

快速开始

压缩一个样式表并打印结果:

curl
curl --data-urlencode 'input=.card { padding: 8px; margin: 0 auto; }' \
  https://formatter.nextwell.top/api/v1/minify/css/raw
# .card{padding:8px;margin:0 auto}

把 {css} 换成 {js} 或 {html},把 {minify} 换成 {beautify}。任意组合都可用。

端点

基础地址是 {base}。下面的接口除非另有说明,都是 POST。

方法 路径 用途
POST/api/v1/minify/{lang}压缩,返回 JSON
POST/api/v1/minify/{lang}/raw压缩,返回纯文本
POST/api/v1/beautify/{lang}格式化,返回 JSON
POST/api/v1/beautify/{lang}/raw格式化,返回纯文本
GET/api/v1/limits查看该 IP 的剩余额度,且不消耗请求
GET/api/v1/health存活检查,不受速率限制

{lang} 是 css、js 或 html 之一。

发送代码

每个端点都接受三种请求体格式,选客户端最方便的那种即可。

表单编码

一个 {input} 字段,{type}。这正是压缩类 API 惯常接受的格式,已有的脚本只需改地址。

curl
curl --data-urlencode 'input=body{margin:0;padding:0}' \
  https://formatter.nextwell.top/api/v1/beautify/css

JSON

{type},其中带有一个 {input} 字符串。

curl
curl -H 'Content-Type: application/json' \
  -d '{"input":"const a=1;const b=a+1;console.log(b)"}' \
  https://formatter.nextwell.top/api/v1/beautify/js

原始请求体

其他任何内容类型:请求体本身就是代码。用 {example} 时很方便。

curl
curl --data-binary @style.css \
  -H 'Content-Type: text/css' \
  https://formatter.nextwell.top/api/v1/minify/css

大小

每次请求 2 MB。超过的请求不会被读取,直接返回 413。

查询参数

名称 取值 含义
engine auto upstream local 由哪个引擎处理这次请求。默认值 {auto} 在额度未用尽时把 CSS 和 JS 的压缩发往上游,用尽后回退到本地。{upstream} 不回退,而是直接报错。{local} 则完全不离开本服务器。
indent 2 4 tab 仅格式化时有效:一级缩进用什么。
curl
curl --data-urlencode 'input=.a{color:red}' \
  'https://formatter.nextwell.top/api/v1/beautify/css?indent=tab&engine=local'

响应

调用成功时返回 JSON:

JSON
{
  "ok": true,
  "action": "minify",
  "language": "css",
  "engine": "upstream",
  "input_bytes": 1024,
  "output_bytes": 640,
  "saved_bytes": 384,
  "saved_percent": 37.5,
  "duration_ms": 42,
  "output": "p{color:red}"
}
字段 类型 含义
okboolean成功时恒为 true。
actionstringminify 或 beautify——请求的是哪种操作。
languagestringcss、js 或 html。
enginestring由外部服务处理时为 upstream,由本服务器处理时为 local。
input_bytesnumber发送内容的大小,单位字节。
output_bytesnumber结果的大小,单位字节。
saved_bytesnumber两者之差;格式化时为负数。
saved_percentnumber同一差值的百分比,保留一位小数。
duration_msnumber处理耗时,单位毫秒。
outputstring处理后的代码。

纯文本响应

在任意一个处理端点后面加上 {raw},响应体就只有结果本身,类型是 {type}。响应头不变。从 shell 调用时很方便:

curl
curl -s --data-binary @app.js \
  -H 'Content-Type: text/javascript' \
  https://formatter.nextwell.top/api/v1/minify/js/raw > app.min.js

响应头

标头 含义
X-Formatter-Engine结果由哪个引擎产生。
X-Formatter-Duration处理耗时,单位毫秒。
X-RateLimit-Remaining-Second-Month该 IP 在每个时间窗口内的剩余额度。
Retry-After出现 429 时:已用尽的窗口中最严格的那个重新开放还需多少秒。
curl
curl -s -D - -o /dev/null --data-urlencode 'input=.a{color:red}' \
  https://formatter.nextwell.top/api/v1/minify/css

错误

所有错误都是 JSON,采用这类 API 惯用的形状,因此已经能处理这种形状的客户端也能处理这里的错误:

JSON
{
  "errors": [
    { "status": 429, "title": "Too many requests", "detail": "…" }
  ]
}
状态码 标题 触发时机
400Missing input Bad request没有请求体,或 input 字段为空。
404Not found路径不存在。
405Method not allowed用 POST 以外的方法调用了处理端点。
413Payload too large请求体超过 2 MB。
415Unsupported language路径中的语言不是 css、js 或 html。
422Malformed input处理器拒绝了这段源码,通常是语法错误。
429Too many requests某个速率限制窗口已用尽,请查看 Retry-After。
502Upstream failed仅在 engine=upstream 时出现:外部服务没有响应。若不指定该参数,这次请求会回退到本地处理。
500Internal error其他情况。

速率限制

按 IP 地址计算,五个滑动窗口同时生效。一次请求必须同时满足这五个窗口。

窗口 上限
每秒{n} 次
每分钟{n} 次
每小时{n} 次
每天{n} 次
每月{n} 次

某个窗口用尽时会返回 429,并带上 Retry-After 响应头,给出最严格的那个窗口重新开放所需的秒数。请求不会排队。

计数器保存在磁盘上的一个小数据库里,因此重启服务不会让任何人重新拿到一整天的额度。

{endpoint} 会返回五个窗口的当前状态,而不消耗任何额度。

curl
curl https://formatter.nextwell.top/api/v1/limits

外部压缩服务对整个站点只允许每分钟 30 次请求,而不是每位访客 30 次。一个共享令牌桶跟踪这个额度:桶空时,CSS 和 JS 的压缩改由本地引擎完成,而不是等待或失败。负载高时可能会看到 engine 字段发生变化——两种情况下输出都同样有效。

由哪个引擎完成处理

两条路径,同一套约定。

云端 — CSS 和 JS 的压缩

一个外部压缩服务,又快又保守:能去掉的空白才去掉,不能去掉的保留下来,所以像 {calc} 这样的写法会原样保留。本服务只是把代码转发过去,不添加任何自己的处理。

本地 — 其余全部

HTML 压缩、三种语言的格式化,以及共享的外部额度用尽或服务被设为不联网时的 CSS/JS 压缩。基于 {tools} 实现,只在请求需要时才加载,因此空闲的进程始终很小。

设置 {param} 可以把某次请求固定到其中一条路径。

会保留什么

什么都不保留。代码只在请求期间留在内存中,之后即被丢弃,不会写入磁盘,也绝不会出现在日志里。日志中记录的只有:IP 的截断哈希、语言、操作、字节数、引擎和耗时。

常见问题

需要密钥吗?

不需要。服务是开放的,改用 IP 地址来限流。

我的代码会被发到别处吗?

CSS 和 JavaScript 的压缩会代理到外部服务,因此这部分代码会离开本服务器。格式化以及全部 HTML 处理都在本服务器完成。设置 engine=local 可以让一切都留在这里。

可以在构建脚本里用吗?

可以,raw 端点就是为此准备的。注意不要超出限制,并留意高负载时引擎可能会回退到本地。

为什么压缩后的 JavaScript 里的名字变了?

上游的压缩器会缩短局部变量名,这是安全的,也是体积缩减的主要来源。格式化并不会把原来的名字找回来——任何工具都做不到。

最大能发送多大的文件?

单次请求 2 MB。更大的文件会被以 413 拒绝,而不是被截断。