846 lines
22 KiB
YAML
846 lines
22 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: Box Manifest API
|
|
version: 0.0.0
|
|
description: >-
|
|
Pre-release API for the Box Manifest universal node tree. Breaking changes
|
|
are allowed until a compatibility policy is adopted.
|
|
servers:
|
|
- url: /
|
|
paths:
|
|
/api/node-types:
|
|
get:
|
|
operationId: listNodeTypes
|
|
summary: List user-defined node types
|
|
responses:
|
|
"200":
|
|
description: Node types ordered by name
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/NodeType" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
post:
|
|
operationId: createNodeType
|
|
summary: Create a node type
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/NodeTypeWrite" }
|
|
responses:
|
|
"201":
|
|
description: Node type created
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/NodeType" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/api/node-types/{typeId}:
|
|
parameters:
|
|
- name: typeId
|
|
in: path
|
|
required: true
|
|
schema: { type: string }
|
|
put:
|
|
operationId: updateNodeType
|
|
summary: Replace a node type
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/NodeTypeWrite" }
|
|
responses:
|
|
"200":
|
|
description: Node type updated
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/NodeType" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
delete:
|
|
operationId: deleteNodeType
|
|
summary: Delete a type and leave assigned nodes untyped
|
|
responses:
|
|
"204": { description: Node type deleted }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/api/tags:
|
|
get:
|
|
operationId: listTags
|
|
summary: List tags
|
|
responses:
|
|
"200":
|
|
description: Tags ordered by name
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Tag" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
post:
|
|
operationId: createTag
|
|
summary: Create a tag
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TagWrite" }
|
|
responses:
|
|
"201":
|
|
description: Tag created
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Tag" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/api/tags/{tagId}:
|
|
parameters:
|
|
- name: tagId
|
|
in: path
|
|
required: true
|
|
schema: { type: string }
|
|
put:
|
|
operationId: updateTag
|
|
summary: Replace a tag
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TagWrite" }
|
|
responses:
|
|
"200":
|
|
description: Tag updated
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Tag" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
delete:
|
|
operationId: deleteTag
|
|
summary: Delete a tag and remove its node assignments
|
|
responses:
|
|
"204": { description: Tag deleted }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/api/tree:
|
|
get:
|
|
operationId: getTree
|
|
summary: Get the complete node tree
|
|
responses:
|
|
"200":
|
|
description: The tree beginning at Root
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TreeNode"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/imports/tree/preview:
|
|
post:
|
|
operationId: previewTreeImport
|
|
summary: Validate and preview a nested tree import
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TreeImportPreviewRequest"
|
|
responses:
|
|
"200":
|
|
description: Normalized import plan ready for review
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TreeImportPreview"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/imports/tree/commit:
|
|
post:
|
|
operationId: commitTreeImport
|
|
summary: Atomically commit a reviewed tree import plan
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TreeImportCommitRequest"
|
|
responses:
|
|
"201":
|
|
description: Entire tree imported
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TreeImportCommitResponse"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes:
|
|
post:
|
|
operationId: createNode
|
|
summary: Create a node
|
|
description: A missing parentId places the new node beneath Unsorted.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateNodeRequest"
|
|
responses:
|
|
"201":
|
|
description: Node created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Node"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/bulk:
|
|
post:
|
|
operationId: createNodesBulk
|
|
summary: Create multiple sibling nodes atomically
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateNodesBulkRequest"
|
|
responses:
|
|
"201":
|
|
description: All nodes created in request order
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateNodesBulkResponse"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/bulk/move:
|
|
post:
|
|
operationId: moveNodesBulk
|
|
summary: Move sibling nodes atomically
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MoveNodesBulkRequest"
|
|
responses:
|
|
"200":
|
|
description: All selected nodes moved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MoveNodesBulkResponse"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/bulk/delete:
|
|
post:
|
|
operationId: deleteNodesBulk
|
|
summary: Delete empty nodes atomically
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DeleteNodesBulkRequest"
|
|
responses:
|
|
"204":
|
|
description: All selected nodes deleted
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/bulk/combine:
|
|
post:
|
|
operationId: combineNodes
|
|
summary: Combine empty sibling nodes into one quantity-tracked node
|
|
description: >-
|
|
The retained node keeps its UUID and lookup code. Other selected nodes
|
|
and their lookup identities are deleted atomically.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CombineNodesRequest"
|
|
responses:
|
|
"200":
|
|
description: Combined quantity-tracked node
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Node"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/bulk/classification:
|
|
post:
|
|
operationId: classifyNodesBulk
|
|
summary: Atomically assign a type and add or remove tags on multiple nodes
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/BulkClassificationRequest" }
|
|
responses:
|
|
"204": { description: Classification updated }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/api/nodes/{nodeId}:
|
|
parameters:
|
|
- $ref: "#/components/parameters/NodeId"
|
|
get:
|
|
operationId: getNode
|
|
summary: Get one node
|
|
responses:
|
|
"200":
|
|
description: Node found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Node"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
patch:
|
|
operationId: updateNode
|
|
summary: Update a node's name or quantity
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UpdateNodeRequest"
|
|
responses:
|
|
"200":
|
|
description: Node updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Node"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
delete:
|
|
operationId: deleteNode
|
|
summary: Delete an empty node
|
|
description: Root, Unsorted, and nodes with children cannot be deleted.
|
|
responses:
|
|
"204":
|
|
description: Node deleted
|
|
"409":
|
|
description: The node is protected or is not empty
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Error"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/by-code/{lookupCode}:
|
|
get:
|
|
operationId: getNodeByLookupCode
|
|
summary: Resolve a printed lookup code to its node
|
|
parameters:
|
|
- name: lookupCode
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: "^[A-Z2-7]{6}$"
|
|
responses:
|
|
"200":
|
|
description: Node found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Node"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/{nodeId}/move:
|
|
parameters:
|
|
- $ref: "#/components/parameters/NodeId"
|
|
post:
|
|
operationId: moveNode
|
|
summary: Move a node
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MoveNodeRequest"
|
|
responses:
|
|
"200":
|
|
description: Node moved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Node"
|
|
"409":
|
|
description: The move is forbidden or would create a cycle
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Error"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/{nodeId}/individualize:
|
|
parameters:
|
|
- $ref: "#/components/parameters/NodeId"
|
|
post:
|
|
operationId: individualizeNode
|
|
summary: Turn an empty quantity node into individually tracked siblings
|
|
description: >-
|
|
The original node becomes the first unit and retains its UUID and lookup
|
|
code. The supplied names must match the existing quantity.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/IndividualizeNodeRequest"
|
|
responses:
|
|
"200":
|
|
description: Individually tracked nodes in unit order
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateNodesBulkResponse"
|
|
default:
|
|
$ref: "#/components/responses/Error"
|
|
/api/nodes/{nodeId}/classification:
|
|
parameters:
|
|
- $ref: "#/components/parameters/NodeId"
|
|
put:
|
|
operationId: classifyNode
|
|
summary: Replace a node's optional type and complete tag set
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/ClassificationRequest" }
|
|
responses:
|
|
"200":
|
|
description: Classified node
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Node" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
components:
|
|
parameters:
|
|
NodeId:
|
|
name: nodeId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
Error:
|
|
description: Request failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Error"
|
|
schemas:
|
|
Node:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- id
|
|
- lookupCode
|
|
- parentId
|
|
- name
|
|
- description
|
|
- quantity
|
|
- typeId
|
|
- tagIds
|
|
properties:
|
|
id:
|
|
type: string
|
|
lookupCode:
|
|
type: string
|
|
description: Stable human-enterable lookup key; not the internal identity.
|
|
pattern: "^[A-Z2-7]{6}$"
|
|
parentId:
|
|
type:
|
|
- string
|
|
- "null"
|
|
description: Null only for Root.
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type:
|
|
- string
|
|
- "null"
|
|
quantity:
|
|
type:
|
|
- integer
|
|
- "null"
|
|
minimum: 0
|
|
typeId:
|
|
type: [string, "null"]
|
|
tagIds:
|
|
type: array
|
|
uniqueItems: true
|
|
items: { type: string }
|
|
ImportNode:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- name
|
|
properties:
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type: string
|
|
quantity:
|
|
type:
|
|
- integer
|
|
- "null"
|
|
minimum: 0
|
|
children:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ImportNode"
|
|
TreeImportManifest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- nodes
|
|
properties:
|
|
nodes:
|
|
type: array
|
|
minItems: 1
|
|
maxItems: 10000
|
|
items:
|
|
$ref: "#/components/schemas/ImportNode"
|
|
TreeImportSummary:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- nodes
|
|
- maximumDepth
|
|
properties:
|
|
nodes:
|
|
type: integer
|
|
minimum: 1
|
|
maximumDepth:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 64
|
|
TreeImportPreviewRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- parentId
|
|
- manifest
|
|
properties:
|
|
parentId:
|
|
type: string
|
|
manifest:
|
|
$ref: "#/components/schemas/TreeImportManifest"
|
|
TreeImportPreview:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- planId
|
|
- summary
|
|
- warnings
|
|
- manifest
|
|
properties:
|
|
planId:
|
|
type: string
|
|
summary:
|
|
$ref: "#/components/schemas/TreeImportSummary"
|
|
warnings:
|
|
type: array
|
|
items:
|
|
type: string
|
|
manifest:
|
|
$ref: "#/components/schemas/TreeImportManifest"
|
|
TreeImportCommitRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- planId
|
|
properties:
|
|
planId:
|
|
type: string
|
|
TreeImportCommitResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- created
|
|
properties:
|
|
created:
|
|
$ref: "#/components/schemas/TreeImportSummary"
|
|
TreeNode:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- id
|
|
- lookupCode
|
|
- parentId
|
|
- name
|
|
- description
|
|
- quantity
|
|
- typeId
|
|
- tagIds
|
|
- children
|
|
properties:
|
|
id:
|
|
type: string
|
|
lookupCode:
|
|
type: string
|
|
pattern: "^[A-Z2-7]{6}$"
|
|
parentId:
|
|
type:
|
|
- string
|
|
- "null"
|
|
description: Null only for Root.
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type:
|
|
- string
|
|
- "null"
|
|
quantity:
|
|
type:
|
|
- integer
|
|
- "null"
|
|
minimum: 0
|
|
typeId:
|
|
type: [string, "null"]
|
|
tagIds:
|
|
type: array
|
|
uniqueItems: true
|
|
items: { type: string }
|
|
children:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/TreeNode"
|
|
CreateNodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- name
|
|
properties:
|
|
parentId:
|
|
type: string
|
|
description: Omit to place the node beneath Unsorted.
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type:
|
|
- string
|
|
- "null"
|
|
quantity:
|
|
type:
|
|
- integer
|
|
- "null"
|
|
minimum: 0
|
|
CreateNodesBulkRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- parentId
|
|
- names
|
|
properties:
|
|
parentId:
|
|
type: string
|
|
names:
|
|
type: array
|
|
minItems: 1
|
|
items:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type:
|
|
- string
|
|
- "null"
|
|
CreateNodesBulkResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- nodes
|
|
properties:
|
|
nodes:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Node"
|
|
MoveNodesBulkRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- nodeIds
|
|
- targetParentId
|
|
properties:
|
|
nodeIds:
|
|
type: array
|
|
minItems: 1
|
|
uniqueItems: true
|
|
items:
|
|
type: string
|
|
targetParentId:
|
|
type: string
|
|
childHandling:
|
|
type: string
|
|
enum:
|
|
- WITH_SUBTREE
|
|
- PROMOTE_CHILDREN
|
|
- CHILDREN_TO_UNSORTED
|
|
default: WITH_SUBTREE
|
|
MoveNodesBulkResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- nodes
|
|
properties:
|
|
nodes:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Node"
|
|
DeleteNodesBulkRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- nodeIds
|
|
properties:
|
|
nodeIds:
|
|
type: array
|
|
minItems: 1
|
|
uniqueItems: true
|
|
items:
|
|
type: string
|
|
IndividualizeNodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- names
|
|
properties:
|
|
names:
|
|
type: array
|
|
minItems: 2
|
|
maxItems: 1000
|
|
items:
|
|
type: string
|
|
minLength: 1
|
|
CombineNodesRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- nodeIds
|
|
- retainedNodeId
|
|
- name
|
|
properties:
|
|
nodeIds:
|
|
type: array
|
|
minItems: 2
|
|
uniqueItems: true
|
|
items:
|
|
type: string
|
|
retainedNodeId:
|
|
type: string
|
|
description: A member of nodeIds whose UUID and lookup code survive.
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
UpdateNodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
minProperties: 1
|
|
properties:
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type:
|
|
- string
|
|
- "null"
|
|
quantity:
|
|
type:
|
|
- integer
|
|
- "null"
|
|
minimum: 0
|
|
NodeType:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [id, name, description, iconKey, color]
|
|
properties:
|
|
id: { type: string }
|
|
name: { type: string, minLength: 1 }
|
|
description: { type: [string, "null"] }
|
|
iconKey: { type: [string, "null"] }
|
|
color: { type: [string, "null"] }
|
|
NodeTypeWrite:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [name]
|
|
properties:
|
|
name: { type: string, minLength: 1 }
|
|
description: { type: [string, "null"] }
|
|
iconKey: { type: [string, "null"] }
|
|
color: { type: [string, "null"] }
|
|
Tag:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [id, name, color]
|
|
properties:
|
|
id: { type: string }
|
|
name: { type: string, minLength: 1 }
|
|
color: { type: [string, "null"] }
|
|
TagWrite:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [name]
|
|
properties:
|
|
name: { type: string, minLength: 1 }
|
|
color: { type: [string, "null"] }
|
|
ClassificationRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [typeId, tagIds]
|
|
properties:
|
|
typeId: { type: [string, "null"] }
|
|
tagIds:
|
|
type: array
|
|
uniqueItems: true
|
|
items: { type: string }
|
|
BulkClassificationRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [nodeIds, setType, typeId, addTagIds, removeTagIds]
|
|
properties:
|
|
nodeIds:
|
|
type: array
|
|
minItems: 1
|
|
uniqueItems: true
|
|
items: { type: string }
|
|
setType: { type: boolean }
|
|
typeId: { type: [string, "null"] }
|
|
addTagIds:
|
|
type: array
|
|
uniqueItems: true
|
|
items: { type: string }
|
|
removeTagIds:
|
|
type: array
|
|
uniqueItems: true
|
|
items: { type: string }
|
|
MoveNodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- targetParentId
|
|
properties:
|
|
targetParentId:
|
|
type: string
|
|
childHandling:
|
|
type: string
|
|
enum:
|
|
- WITH_SUBTREE
|
|
- PROMOTE_CHILDREN
|
|
- CHILDREN_TO_UNSORTED
|
|
default: WITH_SUBTREE
|
|
Error:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- code
|
|
- message
|
|
properties:
|
|
code:
|
|
type: string
|
|
message:
|
|
type: string
|