装配契约文件夹
curl --request POST \
--url https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble \
--header 'Content-Type: application/json' \
--data '{
"files": {}
}'import requests
url = "https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble"
payload = { "files": {} }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({files: {}})
};
fetch('https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({files: {}})
};
fetch('https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble"
payload := strings.NewReader("{\n \"files\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble")
.header("Content-Type", "application/json")
.body("{\n \"files\": {}\n}")
.asString();<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'files' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}require 'uri'
require 'net/http'
url = URI("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"files\": {}\n}"
response = http.request(request)
puts response.read_bodyusing RestSharp;
var options = new RestClientOptions("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddJsonBody("{\n \"files\": {}\n}", false);
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
val client = OkHttpClient()
val mediaType = MediaType.parse("application/json")
val body = RequestBody.create(mediaType, "{\n \"files\": {}\n}")
val request = Request.Builder()
.url("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble")
.post(body)
.addHeader("Content-Type", "application/json")
.build()
val response = client.newCall(request).execute()false{
"manifest": {},
"picked": [
"<string>"
],
"folder_name": "<string>",
"issues": [
{
"path": "<string>",
"message": "<string>"
}
],
"warnings": [
{
"code": "<string>",
"params": {}
}
],
"translations": {
"source": "<string>",
"locales": {}
}
}发布与运营
装配契约文件夹
把契约文件夹的多份 JSON 合并成一份 manifest 并完整校验,匿名可用。
POST
/
v1
/
data-apps
/
contract
/
assemble
装配契约文件夹
curl --request POST \
--url https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble \
--header 'Content-Type: application/json' \
--data '{
"files": {}
}'import requests
url = "https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble"
payload = { "files": {} }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({files: {}})
};
fetch('https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({files: {}})
};
fetch('https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble"
payload := strings.NewReader("{\n \"files\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble")
.header("Content-Type", "application/json")
.body("{\n \"files\": {}\n}")
.asString();<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'files' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}require 'uri'
require 'net/http'
url = URI("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"files\": {}\n}"
response = http.request(request)
puts response.read_bodyusing RestSharp;
var options = new RestClientOptions("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddJsonBody("{\n \"files\": {}\n}", false);
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
val client = OkHttpClient()
val mediaType = MediaType.parse("application/json")
val body = RequestBody.create(mediaType, "{\n \"files\": {}\n}")
val request = Request.Builder()
.url("https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble")
.post(body)
.addHeader("Content-Type", "application/json")
.build()
val response = client.newCall(request).execute()false{
"manifest": {},
"picked": [
"<string>"
],
"folder_name": "<string>",
"issues": [
{
"path": "<string>",
"message": "<string>"
}
],
"warnings": [
{
"code": "<string>",
"params": {}
}
],
"translations": {
"source": "<string>",
"locales": {}
}
}端点
POST https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble
dataapp.json / input_schema.json / output_schema.json / runtime.json / pricing.json / examples.json / README.md(文件名大小写不敏感,input.schema.json 的点号写法也接受并在 picked 中归一)。pricing 与 examples 也可以平铺在 dataapp.json 里。合并后的 manifest 走完整的作者态校验(与校验 manifest 端点同一判定),issues 为空才算可交付。可恢复的异常(缺文件、跨层重名、忽略的非契约文件、文件夹名不匹配等)作为结构化 warnings(code + params,由展示层本地化)返回,不算错误。
硬失败(400):槽位文件不是合法 JSON、形状不对(examples.json 必须是数组,其他槽位是对象)或超过 1MB;一个契约文件都没有;总大小超过 12MB。契约通道只覆盖 api 型,runtime.kind=code 会产生 issue。
可选的第 8 个文件 i18n.json({source, locales},最多 4MB)不并入 manifest,而是解析后作为 translations 返回,由调用方再通过译文端点保存。source 必填;非法语言为 400;等于 source 的语言以 i18n-locale-is-source 跳过;路径级问题以 i18n-* 告警返回。
匿名可用:装配是对请求体的纯函数,不读不写平台数据,没有需要保护的东西;文件与总大小限制是唯一的准入控制。
请求
请求体
object
必填
文件映射,键为相对路径,值为文件文本内容。
示例请求
curl -X POST \
-H "Content-Type: application/json" \
-d '{"files": {"dataapp.json": "{\"spec_version\": \"0.2\", \"identity\": {…}}", "input_schema.json": "{\"type\": \"object\", …}", "output_schema.json": "{\"id_field\": \"review_id\", …}", "runtime.json": "{\"kind\": \"api\", …}", "pricing.json": "{\"events\": [...]}", "examples.json": "[...]", "README.md": "# 商品评论查询"}}' \
"https://api-datahub.bazhuayu.com/v1/data-apps/contract/assemble"
响应
200 成功
{
"data": {
"manifest": {
"spec_version": "0.2",
"identity": {
"app_name": "reviews-query",
"name": "商品评论查询"
},
"…": "…"
},
"picked": {
"dataapp.json": "dataapp.json",
"input_schema.json": "input_schema.json"
},
"issues": [],
"warnings": [
{
"code": "contract-folder-name-mismatch",
"params": {
"expected": "reviews-query",
"actual": "reviews"
}
}
],
"card": {
"app_name": "reviews-query",
"name": "商品评论查询"
},
"translations": null
}
}
data 字段中,其内容如下。
object
必填
合并后的 manifest 对象。
string[]
实际识别到的槽位文件映射。
string
—
错误
| HTTP | code | category | 说明 |
|---|---|---|---|
| 400 | contract-file-invalid | invalid_input | 契约文件不是合法 JSON、形状不对或超过 1MB;或缺少 i18n.json 的 source。 |
| 400 | contract-empty | invalid_input | 文件集合里没有任何契约槽位文件。 |
| 400 | locale-invalid | invalid_input | 语言代码不合法。 |
| 413 | payload-too-large | invalid_input | 请求体超过大小限制。 |
{"error": {code, category, message, retryable}},见错误。
