716 lines
18 KiB
YAML
716 lines
18 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: YAMS Content Store API
|
|
description: |
|
|
HTTP REST API for the YAMS content-addressed storage system.
|
|
|
|
## Features
|
|
- Content-addressed storage with SHA-256 hashing
|
|
- Automatic deduplication
|
|
- Metadata management
|
|
- Batch operations
|
|
- Progress tracking
|
|
|
|
## Authentication
|
|
The API supports multiple authentication methods:
|
|
- **API Key**: Include `X-API-Key` header
|
|
- **Bearer Token**: Include `Authorization: Bearer <token>` header
|
|
- **Basic Auth**: Include `Authorization: Basic <base64>` header
|
|
version: 1.0.0
|
|
contact:
|
|
name: YAMS Team
|
|
url: https://github.com/trvon/yams
|
|
license:
|
|
name: Apache-2.0
|
|
url: https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
servers:
|
|
- url: http://localhost:8080/api/v1
|
|
description: Local development server
|
|
- url: https://api.yams.example.com/api/v1
|
|
description: Production server
|
|
|
|
security:
|
|
- ApiKeyAuth: []
|
|
- BearerAuth: []
|
|
|
|
tags:
|
|
- name: Content
|
|
description: Content storage and retrieval operations
|
|
- name: Metadata
|
|
description: Content metadata management
|
|
- name: Batch
|
|
description: Batch operations
|
|
- name: System
|
|
description: System information and health
|
|
|
|
paths:
|
|
/content:
|
|
post:
|
|
tags:
|
|
- Content
|
|
summary: Store content
|
|
description: Upload a file to the content store
|
|
operationId: storeContent
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
multipart/form-data:
|
|
schema:
|
|
type: object
|
|
required:
|
|
- file
|
|
properties:
|
|
file:
|
|
type: string
|
|
format: binary
|
|
description: The file to upload
|
|
metadata:
|
|
type: string
|
|
description: JSON-encoded metadata
|
|
encoding:
|
|
file:
|
|
contentType: application/octet-stream
|
|
responses:
|
|
"201":
|
|
description: Content stored successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/StoreResponse"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
|
|
/content/{hash}:
|
|
parameters:
|
|
- $ref: "#/components/parameters/ContentHash"
|
|
|
|
get:
|
|
tags:
|
|
- Content
|
|
summary: Retrieve content
|
|
description: Download content by its hash
|
|
operationId: retrieveContent
|
|
parameters:
|
|
- name: Accept
|
|
in: header
|
|
description: |
|
|
Response format:
|
|
- `application/octet-stream` (default) - Returns the file
|
|
- `application/json` - Returns metadata only
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- application/octet-stream
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Content retrieved successfully
|
|
content:
|
|
application/octet-stream:
|
|
schema:
|
|
type: string
|
|
format: binary
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MetadataResponse"
|
|
"404":
|
|
$ref: "#/components/responses/NotFound"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
|
|
delete:
|
|
tags:
|
|
- Content
|
|
summary: Delete content
|
|
description: Remove content from the store
|
|
operationId: deleteContent
|
|
responses:
|
|
"200":
|
|
description: Content deleted successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DeleteResponse"
|
|
"404":
|
|
$ref: "#/components/responses/NotFound"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
|
|
head:
|
|
tags:
|
|
- Content
|
|
summary: Check if content exists
|
|
description: Check if content with given hash exists
|
|
operationId: checkExists
|
|
responses:
|
|
"204":
|
|
description: Content exists
|
|
"404":
|
|
description: Content not found
|
|
|
|
/content/{hash}/metadata:
|
|
parameters:
|
|
- $ref: "#/components/parameters/ContentHash"
|
|
|
|
get:
|
|
tags:
|
|
- Metadata
|
|
summary: Get metadata
|
|
description: Retrieve metadata for content
|
|
operationId: getMetadata
|
|
responses:
|
|
"200":
|
|
description: Metadata retrieved successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MetadataResponse"
|
|
"404":
|
|
$ref: "#/components/responses/NotFound"
|
|
|
|
put:
|
|
tags:
|
|
- Metadata
|
|
summary: Update metadata
|
|
description: Update metadata for content
|
|
operationId: updateMetadata
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ContentMetadata"
|
|
responses:
|
|
"200":
|
|
description: Metadata updated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/SuccessResponse"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"404":
|
|
$ref: "#/components/responses/NotFound"
|
|
|
|
/content/batch:
|
|
post:
|
|
tags:
|
|
- Batch
|
|
summary: Store multiple files
|
|
description: Upload multiple files in a single request
|
|
operationId: storeBatch
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/BatchStoreRequest"
|
|
responses:
|
|
"200":
|
|
description: Batch operation completed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/BatchStoreResponse"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
|
|
delete:
|
|
tags:
|
|
- Batch
|
|
summary: Delete multiple files
|
|
description: Remove multiple files by their hashes
|
|
operationId: deleteBatch
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/BatchDeleteRequest"
|
|
responses:
|
|
"200":
|
|
description: Batch delete completed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/BatchDeleteResponse"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
|
|
/content/search:
|
|
get:
|
|
tags:
|
|
- Content
|
|
summary: Search content
|
|
description: Search for content by metadata
|
|
operationId: searchContent
|
|
parameters:
|
|
- name: mimeType
|
|
in: query
|
|
description: Filter by MIME type
|
|
schema:
|
|
type: string
|
|
- name: namePattern
|
|
in: query
|
|
description: Filter by name pattern (regex)
|
|
schema:
|
|
type: string
|
|
- name: tags
|
|
in: query
|
|
description: Filter by tags (comma-separated)
|
|
schema:
|
|
type: string
|
|
- name: limit
|
|
in: query
|
|
description: Maximum results to return
|
|
schema:
|
|
type: integer
|
|
default: 100
|
|
minimum: 1
|
|
maximum: 1000
|
|
- name: offset
|
|
in: query
|
|
description: Number of results to skip
|
|
schema:
|
|
type: integer
|
|
default: 0
|
|
minimum: 0
|
|
responses:
|
|
"200":
|
|
description: Search results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/SearchResponse"
|
|
|
|
/content/stats:
|
|
get:
|
|
tags:
|
|
- System
|
|
summary: Get statistics
|
|
description: Retrieve storage statistics
|
|
operationId: getStats
|
|
responses:
|
|
"200":
|
|
description: Statistics retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/StatsResponse"
|
|
|
|
/health:
|
|
get:
|
|
tags:
|
|
- System
|
|
summary: Health check
|
|
description: Check system health status
|
|
operationId: healthCheck
|
|
security: [] # No auth required
|
|
responses:
|
|
"200":
|
|
description: System is healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/HealthResponse"
|
|
"503":
|
|
description: System is unhealthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/HealthResponse"
|
|
|
|
components:
|
|
securitySchemes:
|
|
ApiKeyAuth:
|
|
type: apiKey
|
|
in: header
|
|
name: X-API-Key
|
|
description: API key for authentication
|
|
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: JWT bearer token
|
|
|
|
parameters:
|
|
ContentHash:
|
|
name: hash
|
|
in: path
|
|
required: true
|
|
description: SHA-256 hash of the content
|
|
schema:
|
|
type: string
|
|
pattern: "^[a-fA-F0-9]{64}$"
|
|
example: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
|
|
schemas:
|
|
ContentMetadata:
|
|
type: object
|
|
properties:
|
|
mimeType:
|
|
type: string
|
|
description: MIME type of the content
|
|
example: "application/pdf"
|
|
originalName:
|
|
type: string
|
|
description: Original filename
|
|
example: "document.pdf"
|
|
description:
|
|
type: string
|
|
description: Content description
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: Tags for categorization
|
|
example: ["important", "work"]
|
|
customFields:
|
|
type: object
|
|
additionalProperties:
|
|
type: string
|
|
description: Custom metadata fields
|
|
encoding:
|
|
type: string
|
|
description: Character encoding (for text)
|
|
language:
|
|
type: string
|
|
description: Language code
|
|
version:
|
|
type: integer
|
|
description: Version number
|
|
default: 1
|
|
owner:
|
|
type: string
|
|
description: Owner identifier
|
|
permissions:
|
|
type: string
|
|
description: Permission string
|
|
|
|
StoreResult:
|
|
type: object
|
|
required:
|
|
- contentHash
|
|
- bytesStored
|
|
- bytesDeduped
|
|
- dedupRatio
|
|
- duration
|
|
properties:
|
|
contentHash:
|
|
type: string
|
|
description: SHA-256 hash of stored content
|
|
bytesStored:
|
|
type: integer
|
|
format: int64
|
|
description: Total bytes stored
|
|
bytesDeduped:
|
|
type: integer
|
|
format: int64
|
|
description: Bytes saved by deduplication
|
|
dedupRatio:
|
|
type: number
|
|
format: double
|
|
description: Deduplication ratio (0.0-1.0)
|
|
duration:
|
|
type: integer
|
|
format: int64
|
|
description: Operation duration in milliseconds
|
|
|
|
StoreResponse:
|
|
type: object
|
|
required:
|
|
- success
|
|
- data
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
example: true
|
|
data:
|
|
$ref: "#/components/schemas/StoreResult"
|
|
|
|
MetadataResponse:
|
|
type: object
|
|
required:
|
|
- success
|
|
- data
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
type: object
|
|
properties:
|
|
hash:
|
|
type: string
|
|
metadata:
|
|
$ref: "#/components/schemas/ContentMetadata"
|
|
|
|
DeleteResponse:
|
|
type: object
|
|
required:
|
|
- success
|
|
- data
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
type: object
|
|
properties:
|
|
deleted:
|
|
type: boolean
|
|
hash:
|
|
type: string
|
|
|
|
BatchStoreRequest:
|
|
type: object
|
|
required:
|
|
- items
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
type: object
|
|
required:
|
|
- filename
|
|
- content
|
|
properties:
|
|
filename:
|
|
type: string
|
|
content:
|
|
type: string
|
|
format: base64
|
|
description: Base64-encoded file content
|
|
metadata:
|
|
$ref: "#/components/schemas/ContentMetadata"
|
|
|
|
BatchStoreResponse:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
type: object
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
$ref: "#/components/schemas/StoreResult"
|
|
error:
|
|
type: string
|
|
|
|
BatchDeleteRequest:
|
|
type: object
|
|
required:
|
|
- hashes
|
|
properties:
|
|
hashes:
|
|
type: array
|
|
items:
|
|
type: string
|
|
pattern: "^[a-fA-F0-9]{64}$"
|
|
|
|
BatchDeleteResponse:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
type: object
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
hash:
|
|
type: string
|
|
deleted:
|
|
type: boolean
|
|
error:
|
|
type: string
|
|
|
|
SearchResponse:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
type: object
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
hash:
|
|
type: string
|
|
metadata:
|
|
$ref: "#/components/schemas/ContentMetadata"
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
|
|
ContentStats:
|
|
type: object
|
|
properties:
|
|
totalObjects:
|
|
type: integer
|
|
format: int64
|
|
totalBytes:
|
|
type: integer
|
|
format: int64
|
|
uniqueBlocks:
|
|
type: integer
|
|
format: int64
|
|
deduplicatedBytes:
|
|
type: integer
|
|
format: int64
|
|
dedupRatio:
|
|
type: number
|
|
format: double
|
|
storeOperations:
|
|
type: integer
|
|
format: int64
|
|
retrieveOperations:
|
|
type: integer
|
|
format: int64
|
|
deleteOperations:
|
|
type: integer
|
|
format: int64
|
|
lastOperation:
|
|
type: string
|
|
format: date-time
|
|
|
|
StatsResponse:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
$ref: "#/components/schemas/ContentStats"
|
|
|
|
HealthStatus:
|
|
type: object
|
|
properties:
|
|
isHealthy:
|
|
type: boolean
|
|
status:
|
|
type: string
|
|
warnings:
|
|
type: array
|
|
items:
|
|
type: string
|
|
errors:
|
|
type: array
|
|
items:
|
|
type: string
|
|
lastCheck:
|
|
type: string
|
|
format: date-time
|
|
|
|
HealthResponse:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
data:
|
|
$ref: "#/components/schemas/HealthStatus"
|
|
|
|
SuccessResponse:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
example: true
|
|
message:
|
|
type: string
|
|
|
|
ErrorResponse:
|
|
type: object
|
|
required:
|
|
- error
|
|
- message
|
|
- code
|
|
properties:
|
|
error:
|
|
type: string
|
|
description: Error type
|
|
message:
|
|
type: string
|
|
description: Human-readable error message
|
|
code:
|
|
type: integer
|
|
description: HTTP status code
|
|
requestId:
|
|
type: string
|
|
description: Request ID for tracking
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: Bad request
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: Bad Request
|
|
message: Invalid request parameters
|
|
code: 400
|
|
requestId: 123e4567-e89b-12d3-a456-426614174000
|
|
|
|
Unauthorized:
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: Unauthorized
|
|
message: Invalid or missing authentication credentials
|
|
code: 401
|
|
requestId: 123e4567-e89b-12d3-a456-426614174000
|
|
|
|
NotFound:
|
|
description: Not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: Not Found
|
|
message: Content not found
|
|
code: 404
|
|
requestId: 123e4567-e89b-12d3-a456-426614174000
|
|
|
|
InternalError:
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: Internal Server Error
|
|
message: An unexpected error occurred
|
|
code: 500
|
|
requestId: 123e4567-e89b-12d3-a456-426614174000
|