开始之前
该 API 可通过游客会话在无账户情况下使用。API 位于站点自身地址下的 /api。只需设置一次:
API=https://dev.uliketechnology.com/api
F=board.zip
board.zip 是将 Gerber文件和钻孔文件平铺打包的 zip 文件。其中应包含哪些文件,见用于生产和组装的文件。示例需要用到 curl 和 jq。
游客会话之后,对 API 的每个请求都需带上 Authorization: Bearer <token>。每个错误的格式都相同:
{ "error": { "code": "VALIDATION_FAILED", "message": "…", "details": {}, "requestId": "…" } }
应根据 code 进行分支处理。message 是给开发者看的。
- 游客会话: 令牌仅显示一次。
- 上传: 使用 API 指定的请求头,将 zip 文件通过
PUT发送到 API 指定的地址。 - 完成上传, 然后轮询,直到分析完成。
- 报告: 问题、已运行了哪些检查以及哪些检查未运行。
- 报价预览。
使用 curl 的流程
读取可订购的内容。此操作不需要令牌:
curl -s $API/v1/capabilities | jq '.options[].id'
开启游客会话。令牌仅显示一次,有效期为 30 天:
T=$(curl -s -X POST $API/v1/guest-sessions | jq -r .token)
声明要上传的文件。响应包含 uploadId、designId、uploadUrl 和 requiredHeaders:
J=$(curl -s -X POST $API/v1/uploads -H "authorization: Bearer $T" -H 'content-type: application/json' \
-d "{\"fileName\":\"board.zip\",\"sizeBytes\":$(stat -c %s $F),\"sha256\":\"$(sha256sum $F | cut -d' ' -f1)\",\"purpose\":\"design\"}")
将文件发送到响应指定的地址,并带上 requiredHeaders 中的每个请求头(内容类型、长度和校验和;缺少这些请求头时,上传会以 403 被拒绝)。然后完成上传:
curl -s -X PUT --data-binary @$F \
$(echo $J | jq -r '.requiredHeaders | to_entries[] | "-H \(.key):\(.value)"') \
"$(echo $J | jq -r .uploadUrl)"
curl -s -X POST $API/v1/uploads/$(echo $J | jq -r .uploadId)/complete -H "authorization: Bearer $T" | jq .design.status
状态最初为 analysing。持续读取该设计,直到状态改变。当状态为 ready 时,报告包含在响应中:
D=$(echo $J | jq -r .designId)
curl -s $API/v1/designs/$D -H "authorization: Bearer $T" | jq '.design.status, .report.headline, .report.counts'
headline 为 no_problems_in_checks_run、problems_found 或 could_not_check。同时读取 checksRun 和 checksNotRun:未运行的检查不算通过。其他状态还有 needs_mapping(使用 PUT /v1/designs/{designId}/layer-mapping 设置层)、needs_engineer 和 rejected。
请求价格预览。selection 和 destinationCountry 为必填项;selection 为空时使用默认值:
curl -s -X POST $API/v1/quote-previews -H "authorization: Bearer $T" -H 'content-type: application/json' \
-d "{\"designId\":\"$D\",\"quantities\":{\"boardsFabricated\":10,\"boardsAssembled\":0},\"selection\":{},\"destinationCountry\":\"DE\"}" \
| jq '.mode, .reviewReasons, .totalMinor'
mode 为 instant(价格即为显示价格)或 review(由工程师确认);reviewReasons 说明原因。totalMinor 以响应中 currency 的最小单位表示,当需要工程师为该工作报价时该字段不存在。要保存报价,POST /v1/quotes 使用相同的请求体。
使用 JavaScript 客户端的相同流程
@ulike/sdk 客户端封装了这些路由。它尚未作为软件包发布;以下展示其形式,以便使用 fetch 编写相同的调用。方法名:
import { createClient } from '@ulike/sdk';
let token;
const api = createClient({ baseUrl: 'https://dev.uliketechnology.com/api', token: () => token });
const caps = await api.capabilities();
token = (await api.createGuestSession()).token;
const started = await api.uploadDesign({ name: 'board.zip', bytes }); // announce, PUT, complete
const view = await api.waitForDesign(started.design.id); // polls getDesign
const preview = await api.previewQuote({
designId: view.design.id,
quantities: { boardsFabricated: 10, boardsAssembled: 0 },
selection: {},
destinationCountry: 'DE',
});
其他方法包括 createUpload、completeUpload、getDesign、setLayerMapping、validateDesign、getValidation、waitForValidation、createQuote、getQuote 和 reviseQuote。错误以 ApiClientError 形式抛出,并带有 status 和 code。
针对订单的检查
上传后得到的报告仅基于文件本身生成。要根据订单检查文件,请调用 POST /v1/designs/{designId}/validations(validateDesign),其中 order 包含 quantities 和 selection。响应是一个状态:running、failed 或 done。在 running 期间,每隔一两秒读取一次 GET /v1/validations/{reportId}(getValidation),直到状态为 done。
- 上传 zip 文件。
- 读取报告。
- 修改后作为新设计上传。 当修改会改变功能、价格或交期时,停下来询问委托人。
- 文件无问题: 针对订单运行检查。
带有引入其他限制的选项(铜更厚、另一种厚度)的报价或预览,需要针对该选择进行检查。如果不存在这样的检查,系统会启动一项,预览会带有审核原因 file_check_pending 和一个带有其 reportId 的 check。价格会立即显示,但报价会保持 review 状态,直到该检查完成。按上文所述读取检查结果,然后再次请求预览。
会遇到的错误
| 代码 | 状态 | 含义 | 应怎么做 |
|---|---|---|---|
DESIGN_NOT_READY |
422 | 设计仍在读取中(details.status 说明当前处于哪个状态),或还没有报告。 |
持续读取设计,直到状态不再是 analysing,然后再次请求。 |
VALIDATION_FAILED |
400 | 请求格式不符合预期,或指定了目录中没有的选项或值。details 列出问题或异常。 |
修改 details 中指出的字段并重新发送。选项 id 和值从 GET /v1/capabilities 获取。 |
NOT_MANUFACTURABLE |
422 | 所选组合不是我们生产的产品。details.because 包含原因。 |
更改选择;不要重试相同的选择。如果更改会改变电路板,请询问委托人。 |
ANONYMOUS_BUDGET_SPENT |
429 | 无账户时的每日额度已用完。details.resetsOn 为重置日期。 |
停下来。告知委托人;委托人可以登录或等到该日期。 |
REVISION_CONFLICT |
409 | 某次修订指定的基础版本已不再是报价的最新版本。details 包含两个 head 值。 |
使用 GET /v1/quotes/{quoteId} 读取 head,在其基础上重新应用更改,然后重新发送。 |
还可能出现 DESIGN_REJECTED(上传被拒绝;见 details.reason)、因令牌缺失或错误而出现的 UNAUTHENTICATED(错误的令牌即使在公开路由上也会被拒绝),以及针对尚未开放路由的 FEATURE_DISABLED。
无账户时的每日额度
游客会话有每日计算额度。上传和已启动的检查比普通读取消耗更多,从同一网络地址开启许多游客会话也被计入。站点为新选择自动启动的检查从同一额度中扣除。额度用完时,会收到 ANONYMOUS_BUDGET_SPENT 以及重置日期。已登录的调用方不按此方式计数。
目前 API 尚不能做的事:下单、付款、API 密钥以及供智能体使用的登录功能均为计划中功能,尚不可用。计划中的 MCP 服务器见什么是 MCP 以及智能体如何下单。