文档
餐厅自己的文档库——证书、操作规程、报告——每条记录都是一份归档的文件,各有自己的媒体类型。
每家餐厅在那些查验之外都还留着纸:供应商证书、清洁规程、上一次检查的报告、一份 签过字的计划。应用给了他们一个地方把这些归档,而这个集合就是那个档案柜——每份 文档一条记录,每一条都指向那个文件本身。
| 集合 | 权限范围 | 一条记录是什么 |
|---|---|---|
drive-files | drive-files:read | 一份归档在这家餐厅文档库里的文档。 |
它共用那个快照信封:id、deleted、capturedAt、
receivedAt、sequence 以及其余字段,都围在下面的 data 周围。
drive-files
| 字段 | 类型 | 含义 |
|---|---|---|
s3Key | string, 必填 | 这份文档在库里的位置。是一个键,不是一个 URL。最长 1024 个字符。 |
name | string, 必填 | 餐厅看到的那个文件名。 |
sizeBytes | number, 必填 | 这份文档的大小,以字节计。 |
contentType | string | null | 应用记下的那个媒体类型。可能缺失。 |
asset | object | 那个文件。请读下一节。 |
{
"id": "a94c7e51-3f60-4b2d-8e17-05c9d3a6f482",
"collection": "drive-files",
"deleted": false,
"capturedAt": "1789743015220",
"receivedAt": "1789743098644",
"sequence": "97",
"data": {
"s3Key": "drive/fournisseurs/attestation-metro-2026.pdf",
"name": "Attestation Metro 2026.pdf",
"sizeBytes": 184320,
"contentType": "application/pdf",
"asset": {
"objectKey": "restaurants/36eaa3fa/drive/a17c93be4f02",
"status": "uploaded",
"contentType": "application/pdf",
"byteLength": 184320,
"sha256": "9f2a7c41e8b0d5364a1f8e29b7c30d5e6f14a8b29c7d0e3f5a6b1c8d9e0f2a3b"
}
}
}
data 里没有 timestamp。这份文档是什么时候归档的,是信封上的 capturedAt,和
其他每一个集合一样。
文件才是重点
在别处,记录是信息,文件是凭证。这里正好反过来:五个字段描述一份文档,而这份文档 的内容,才是任何人来读这个集合的全部理由。所以你几乎总是会顺着记录走到字节那边 去。
GET /v1/restaurants/{restaurantId}/collections/drive-files/records/{recordId}/assets
签名 URL,有效十五分钟,每个都自带授权。集合那一页上有 那些规则,而其中两条在这里比在别处更要紧:
sha256能让你省掉一次下载。 它是这些字节的摘要。一份自你上次遍历以来没有 变过的证书,不需要再取一次,而文档是这个 API 会交给你的最大的东西。- 现在就取,存字节,绝不要存链接。 十五分钟长到足够下载完,也短到让你数据库里 的一个 URL 到第二天早上就成了一条死链。
asset 描述这个文件;但只有那个端点会把它交给你。 它带着 objectKey、
status、contentType、byteLength 和 sha256——足够你决定要不要这些字节——
但没有 URL,因为一个永不过期的 URL,会成为一条通往一家餐厅文书资料的、永久的、
不需要认证的链接。
status 是你该拿来分支的那个字段。字节落地并通过校验之后它是 uploaded,而在
某台设备还在发送它们的时候是 pending。一个 pending 的附件不会出现在 assets
端点里,这是正确的行为,而不是坏掉了:过一会儿再问一次,而不要把它当成一份丢失的
文档。asset 也是这里唯一一个可以整个缺席的字段——一条还没有文件的归档记录。
这些不是图片
一份清洁凭证是一张照片。而一份文档是餐厅归档进来的任何东西:一份 PDF 证书、一份 Excel 或 CSV 的温度导出、一份 Word 规程、某人用手机扫的一张扫描件。它们全都会出现 在这里。
请读 contentType,而不要假定一个。 它在记录里可以为 null——应用并不总是有
它——所以当它是 null 时,改用附件上的那个 contentType;那一个是真正被存下来的那
个对象的媒体类型,而且在两者不一致的时候,它才是该信的那个。一个把所有东西都渲染
成图片、或者把所有东西都存成 .pdf 的客户端,会在遇到第一份表格时就坏掉。
也不要从 name 或 s3Key 推出类型。 扩展名是一个惯例,不是一个保证,而这两
个字段都是一个人在平板上给文件起名时打出来的自由文本。
在你这边归档它们
s3Key 是一个键,不是一个地址。 它在库里标识那个对象——它没有协议、没有主
机,也没有开头的斜杠,而且你没法拿它去取东西。你拿到的每一个字节都来自 assets
端点。
以信封上的 id 为键,而不是 name。 没有任何东西阻止两份文档都叫
Attestation 2026.pdf,在同一家餐厅里,相隔一年归档。
在下载之前,sizeBytes 值得一读。 它是决定要不要在移动网络上拉一份 40 MB
扫描件的最廉价的办法。而被存下来的那个对象自己的 byteLength,在附件上,才是权威
的那一个。
一块墓碑会把文件一起带走。 deleted: true 意味着这份文档在应用里被删除了,
它的附件也不再被列出——如果你当时需要那份证书,你需要的是那些字节。墓碑是怎么表现
的,见信封那一页。