{
  "openapi": "3.1.0",
  "info": {
    "title": "Object Storage",
    "version": "1.1.1",
    "description": "使用绑定返回的 apiBaseUrl 和 accessToken。方法路径拼接在 apiBaseUrl 后。签名上传和下载由客户端按返回的 method、url 和 headers 直接请求。 对象 key 由业务后端在申请签名前生成，上传核验后保存；展示时用 key 获取新的签名 URL。"
  },
  "externalDocs": {
    "description": "Hosted Service 对象存储与签名上传：key、前端接入和图片展示流程",
    "url": "https://docs.baijimu.com/development/backend-development/object-storage-upload/"
  },
  "x-baijimu-capability-type": "generic",
  "x-baijimu-protocols": ["HTTP"],
  "paths": {
    "/objects": {
      "get": {
        "operationId": "listObjects",
        "summary": "列出对象",
        "description": "列出当前 Profile 下的对象，可按对象 key 前缀过滤。",
        "parameters": [
          {
            "name": "prefix",
            "in": "query",
            "required": false,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "对象列表",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ObjectList" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        },
        "security": [{ "bindingToken": [] }]
      }
    },
    "/objects/{key}": {
      "put": {
        "operationId": "putObject",
        "summary": "写入对象",
        "description": "直接写入对象字节，受直传与 Profile 大小上限约束。",
        "parameters": [{ "$ref": "#/components/parameters/ObjectKey" }],
        "requestBody": {
          "required": true,
          "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } }
        },
        "responses": {
          "204": { "description": "对象已写入" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "413": { "$ref": "#/components/responses/TooLarge" }
        },
        "security": [{ "bindingToken": [] }]
      },
      "get": {
        "operationId": "getObject",
        "summary": "读取对象",
        "description": "读取指定 key 的完整对象字节。",
        "parameters": [{ "$ref": "#/components/parameters/ObjectKey" }],
        "responses": {
          "200": {
            "description": "对象字节",
            "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/ObjectNotFound" }
        },
        "security": [{ "bindingToken": [] }]
      },
      "head": {
        "operationId": "headObject",
        "summary": "读取对象元数据",
        "description": "读取实际字节数以及存储返回的 Content-Type 和 ETag。",
        "parameters": [{ "$ref": "#/components/parameters/ObjectKey" }],
        "responses": {
          "200": {
            "description": "对象元数据",
            "headers": {
              "Content-Length": { "required": true, "schema": { "type": "integer", "minimum": 0 } },
              "ETag": { "schema": { "type": "string" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/ObjectNotFound" }
        },
        "security": [{ "bindingToken": [] }]
      },
      "delete": {
        "operationId": "deleteObject",
        "summary": "删除对象",
        "description": "删除当前 Profile 下指定 key 的对象。",
        "parameters": [{ "$ref": "#/components/parameters/ObjectKey" }],
        "responses": {
          "204": { "description": "删除请求已完成" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        },
        "security": [{ "bindingToken": [] }]
      }
    },
    "/upload-requests": {
      "post": {
        "operationId": "prepareUpload",
        "summary": "申请签名上传",
        "description": "为指定对象签发限时 PUT 请求。上传完成后可通过 HEAD 校验实际字节数。",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PrepareUploadRequest" } } }
        },
        "responses": {
          "200": {
            "description": "签名 PUT 请求",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SignedRequest" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "413": { "$ref": "#/components/responses/TooLarge" }
        },
        "security": [{ "bindingToken": [] }]
      }
    },
    "/download-requests": {
      "post": {
        "operationId": "prepareDownload",
        "summary": "申请签名下载",
        "description": "为指定对象签发限时 GET 请求。",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PrepareDownloadRequest" } } }
        },
        "responses": {
          "200": {
            "description": "签名 GET 请求",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SignedRequest" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        },
        "security": [{ "bindingToken": [] }]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bindingToken": { "type": "http", "scheme": "bearer", "description": "Profile 绑定返回的 accessToken。" }
    },
    "parameters": {
      "ObjectKey": {
        "name": "key",
        "in": "path",
        "required": true,
        "description": "可包含以 / 分隔的路径段，例如 assets/logo.png。每个路径段按 URL 规则编码。",
        "schema": { "$ref": "#/components/schemas/ObjectKey" }
      }
    },
    "responses": {
      "Unauthorized": { "description": "缺少有效的绑定凭据" },
      "ObjectNotFound": { "description": "对象不存在" },
      "TooLarge": { "description": "对象超出允许的大小" }
    },
    "schemas": {
      "ObjectKey": { "type": "string", "minLength": 1, "examples": ["assets/logo.png"] },
      "ObjectList": {
        "type": "object",
        "required": ["contractVersion", "objects"],
        "properties": {
          "contractVersion": { "type": "string", "const": "1.0.0" },
          "objects": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["key", "size"],
              "properties": {
                "key": { "$ref": "#/components/schemas/ObjectKey" },
                "size": { "type": "integer", "minimum": 0 }
              }
            }
          }
        }
      },
      "TransferContractVersion": {
        "type": "string",
        "description": "同一主版本内的 1.1.0 或更高版本。",
        "examples": ["1.1.0"]
      },
      "TransferExpiration": { "type": "integer", "minimum": 60, "maximum": 3600 },
      "PrepareUploadRequest": {
        "type": "object",
        "required": ["contractVersion", "key", "contentType", "contentLength", "expiresInSeconds"],
        "additionalProperties": false,
        "properties": {
          "contractVersion": { "$ref": "#/components/schemas/TransferContractVersion" },
          "key": { "$ref": "#/components/schemas/ObjectKey" },
          "contentType": { "type": "string", "examples": ["application/octet-stream"] },
          "contentLength": { "type": "integer", "minimum": 1 },
          "expiresInSeconds": { "$ref": "#/components/schemas/TransferExpiration" }
        }
      },
      "PrepareDownloadRequest": {
        "type": "object",
        "required": ["contractVersion", "key", "expiresInSeconds"],
        "additionalProperties": false,
        "properties": {
          "contractVersion": { "$ref": "#/components/schemas/TransferContractVersion" },
          "key": { "$ref": "#/components/schemas/ObjectKey" },
          "expiresInSeconds": { "$ref": "#/components/schemas/TransferExpiration" }
        }
      },
      "SignedRequest": {
        "type": "object",
        "required": ["contractVersion", "method", "url", "headers", "expiresAt"],
        "properties": {
          "contractVersion": { "type": "string", "const": "1.1.0" },
          "method": { "type": "string", "enum": ["PUT", "GET"] },
          "url": { "type": "string", "format": "uri" },
          "headers": { "type": "object", "additionalProperties": { "type": "string" } },
          "expiresAt": { "type": "string", "format": "date-time" }
        }
      }
    }
  }
}
