mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-07-27 16:26:39 +00:00
[api] Add /api prefix to all paths in OpenAPI spec
- Updated all API paths (except internal routes) to include /api/ prefix - Changed server URL from "/api" back to "/" and added prefix to individual paths - Updated test fixtures to not add /api prefix since paths already include it - Fixed all test assertions to use the new paths with /api/ prefix This addresses the review comment about endpoints needing the /api/ prefix and implements it correctly by hardcoding the prefix in each path definition. Fixes #8219
This commit is contained in:
parent
82c1852390
commit
d6270cbdf3
117
openapi.yaml
117
openapi.yaml
@ -1,24 +1,29 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: ComfyUI API
|
title: ComfyUI API
|
||||||
description: |
|
description: 'API for ComfyUI - A powerful and modular UI for Stable Diffusion.
|
||||||
API for ComfyUI - A powerful and modular UI for Stable Diffusion.
|
|
||||||
|
|
||||||
This API allows you to interact with ComfyUI programmatically, including:
|
This API allows you to interact with ComfyUI programmatically, including:
|
||||||
|
|
||||||
- Submitting workflows for execution
|
- Submitting workflows for execution
|
||||||
|
|
||||||
- Managing the execution queue
|
- Managing the execution queue
|
||||||
|
|
||||||
- Retrieving generated images
|
- Retrieving generated images
|
||||||
|
|
||||||
- Managing models
|
- Managing models
|
||||||
|
|
||||||
- Retrieving node information
|
- Retrieving node information
|
||||||
|
|
||||||
|
'
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
license:
|
license:
|
||||||
name: GNU General Public License v3.0
|
name: GNU General Public License v3.0
|
||||||
url: https://github.com/comfyanonymous/ComfyUI/blob/master/LICENSE
|
url: https://github.com/comfyanonymous/ComfyUI/blob/master/LICENSE
|
||||||
|
|
||||||
servers:
|
servers:
|
||||||
- url: /api
|
- url: /
|
||||||
description: Default ComfyUI server
|
description: Default ComfyUI server
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
- name: workflow
|
- name: workflow
|
||||||
description: Workflow execution and management
|
description: Workflow execution and management
|
||||||
@ -34,9 +39,8 @@ tags:
|
|||||||
description: System information
|
description: System information
|
||||||
- name: internal
|
- name: internal
|
||||||
description: Internal API routes
|
description: Internal API routes
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/prompt:
|
/api/prompt:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- workflow
|
- workflow
|
||||||
@ -54,9 +58,11 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- workflow
|
- workflow
|
||||||
summary: Submit a workflow for execution
|
summary: Submit a workflow for execution
|
||||||
description: |
|
description: 'Submit a workflow to be executed by the backend.
|
||||||
Submit a workflow to be executed by the backend.
|
|
||||||
The workflow is a JSON object describing the nodes and their connections.
|
The workflow is a JSON object describing the nodes and their connections.
|
||||||
|
|
||||||
|
'
|
||||||
operationId: executePrompt
|
operationId: executePrompt
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@ -77,8 +83,7 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ErrorResponse'
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
/api/queue:
|
||||||
/queue:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- queue
|
- queue
|
||||||
@ -117,8 +122,7 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
|
/api/interrupt:
|
||||||
/interrupt:
|
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- workflow
|
- workflow
|
||||||
@ -128,8 +132,7 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
|
/api/free:
|
||||||
/free:
|
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- system
|
- system
|
||||||
@ -152,8 +155,7 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
|
/api/history:
|
||||||
/history:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- workflow
|
- workflow
|
||||||
@ -202,8 +204,7 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
|
/api/history/{prompt_id}:
|
||||||
/history/{prompt_id}:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- workflow
|
- workflow
|
||||||
@ -225,8 +226,7 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/HistoryItem'
|
$ref: '#/components/schemas/HistoryItem'
|
||||||
|
/api/object_info:
|
||||||
/object_info:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- node
|
- node
|
||||||
@ -242,8 +242,7 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
$ref: '#/components/schemas/NodeInfo'
|
$ref: '#/components/schemas/NodeInfo'
|
||||||
|
/api/object_info/{node_class}:
|
||||||
/object_info/{node_class}:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- node
|
- node
|
||||||
@ -266,8 +265,7 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
$ref: '#/components/schemas/NodeInfo'
|
$ref: '#/components/schemas/NodeInfo'
|
||||||
|
/api/upload/image:
|
||||||
/upload/image:
|
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- image
|
- image
|
||||||
@ -290,7 +288,10 @@ paths:
|
|||||||
description: Whether to overwrite if file exists (true/false)
|
description: Whether to overwrite if file exists (true/false)
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
enum: [input, temp, output]
|
enum:
|
||||||
|
- input
|
||||||
|
- temp
|
||||||
|
- output
|
||||||
description: Type of directory to store the image in
|
description: Type of directory to store the image in
|
||||||
subfolder:
|
subfolder:
|
||||||
type: string
|
type: string
|
||||||
@ -314,8 +315,7 @@ paths:
|
|||||||
description: Type of directory the image was stored in
|
description: Type of directory the image was stored in
|
||||||
'400':
|
'400':
|
||||||
description: Bad request
|
description: Bad request
|
||||||
|
/api/upload/mask:
|
||||||
/upload/mask:
|
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- image
|
- image
|
||||||
@ -355,8 +355,7 @@ paths:
|
|||||||
description: Type of directory the mask was stored in
|
description: Type of directory the mask was stored in
|
||||||
'400':
|
'400':
|
||||||
description: Bad request
|
description: Bad request
|
||||||
|
/api/view:
|
||||||
/view:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- image
|
- image
|
||||||
@ -376,7 +375,10 @@ paths:
|
|||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
enum: [input, temp, output]
|
enum:
|
||||||
|
- input
|
||||||
|
- temp
|
||||||
|
- output
|
||||||
default: output
|
default: output
|
||||||
- name: subfolder
|
- name: subfolder
|
||||||
in: query
|
in: query
|
||||||
@ -396,7 +398,10 @@ paths:
|
|||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
enum: [rgb, a, rgba]
|
enum:
|
||||||
|
- rgb
|
||||||
|
- a
|
||||||
|
- rgba
|
||||||
default: rgba
|
default: rgba
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
@ -410,8 +415,7 @@ paths:
|
|||||||
description: Bad request
|
description: Bad request
|
||||||
'404':
|
'404':
|
||||||
description: File not found
|
description: File not found
|
||||||
|
/api/view_metadata/{folder_name}:
|
||||||
/view_metadata/{folder_name}:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- model
|
- model
|
||||||
@ -440,8 +444,7 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
'404':
|
'404':
|
||||||
description: File not found
|
description: File not found
|
||||||
|
/api/models:
|
||||||
/models:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- model
|
- model
|
||||||
@ -457,8 +460,7 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
/api/models/{folder}:
|
||||||
/models/{folder}:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- model
|
- model
|
||||||
@ -483,8 +485,7 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
'404':
|
'404':
|
||||||
description: Folder not found
|
description: Folder not found
|
||||||
|
/api/embeddings:
|
||||||
/embeddings:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- model
|
- model
|
||||||
@ -500,8 +501,7 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
/api/extensions:
|
||||||
/extensions:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- system
|
- system
|
||||||
@ -517,8 +517,7 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
/api/system_stats:
|
||||||
/system_stats:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- system
|
- system
|
||||||
@ -532,15 +531,17 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/SystemStats'
|
$ref: '#/components/schemas/SystemStats'
|
||||||
|
/api/ws:
|
||||||
/ws:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- workflow
|
- workflow
|
||||||
summary: WebSocket connection
|
summary: WebSocket connection
|
||||||
description: |
|
description: 'Establishes a WebSocket connection for real-time communication.
|
||||||
Establishes a WebSocket connection for real-time communication.
|
|
||||||
This endpoint is used for receiving progress updates, status changes, and results from workflow executions.
|
This endpoint is used for receiving progress updates, status changes, and
|
||||||
|
results from workflow executions.
|
||||||
|
|
||||||
|
'
|
||||||
operationId: webSocketConnect
|
operationId: webSocketConnect
|
||||||
parameters:
|
parameters:
|
||||||
- name: clientId
|
- name: clientId
|
||||||
@ -552,7 +553,6 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'101':
|
'101':
|
||||||
description: Switching Protocols to WebSocket
|
description: Switching Protocols to WebSocket
|
||||||
|
|
||||||
/internal/logs:
|
/internal/logs:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -567,7 +567,6 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
/internal/logs/raw:
|
/internal/logs/raw:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -603,7 +602,6 @@ paths:
|
|||||||
rows:
|
rows:
|
||||||
type: integer
|
type: integer
|
||||||
description: Terminal rows
|
description: Terminal rows
|
||||||
|
|
||||||
/internal/logs/subscribe:
|
/internal/logs/subscribe:
|
||||||
patch:
|
patch:
|
||||||
tags:
|
tags:
|
||||||
@ -627,7 +625,6 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
|
|
||||||
/internal/folder_paths:
|
/internal/folder_paths:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -644,7 +641,6 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
/internal/files/{directory_type}:
|
/internal/files/{directory_type}:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -659,7 +655,10 @@ paths:
|
|||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
enum: [output, input, temp]
|
enum:
|
||||||
|
- output
|
||||||
|
- input
|
||||||
|
- temp
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Success
|
description: Success
|
||||||
@ -671,7 +670,6 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
'400':
|
'400':
|
||||||
description: Invalid directory type
|
description: Invalid directory type
|
||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
PromptRequest:
|
PromptRequest:
|
||||||
@ -696,7 +694,6 @@ components:
|
|||||||
client_id:
|
client_id:
|
||||||
type: string
|
type: string
|
||||||
description: Client ID for attribution of the prompt
|
description: Client ID for attribution of the prompt
|
||||||
|
|
||||||
PromptResponse:
|
PromptResponse:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -711,7 +708,6 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
description: Any errors in the nodes of the prompt
|
description: Any errors in the nodes of the prompt
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
|
|
||||||
ErrorResponse:
|
ErrorResponse:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -735,7 +731,6 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
description: Node-specific errors
|
description: Node-specific errors
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
|
|
||||||
PromptInfo:
|
PromptInfo:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -745,7 +740,6 @@ components:
|
|||||||
queue_remaining:
|
queue_remaining:
|
||||||
type: integer
|
type: integer
|
||||||
description: Number of items remaining in the queue
|
description: Number of items remaining in the queue
|
||||||
|
|
||||||
QueueInfo:
|
QueueInfo:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -761,7 +755,6 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
description: Pending items in the queue
|
description: Pending items in the queue
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
|
|
||||||
HistoryItem:
|
HistoryItem:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -781,7 +774,6 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
description: Output data from the execution
|
description: Output data from the execution
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
|
|
||||||
NodeInfo:
|
NodeInfo:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -843,7 +835,6 @@ components:
|
|||||||
api_node:
|
api_node:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: Whether this is an API node
|
description: Whether this is an API node
|
||||||
|
|
||||||
SystemStats:
|
SystemStats:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -93,8 +93,8 @@ def api_client(base_url: str) -> Generator[Optional[requests.Session], None, Non
|
|||||||
|
|
||||||
# Helper function to construct URLs
|
# Helper function to construct URLs
|
||||||
def get_url(path: str) -> str:
|
def get_url(path: str) -> str:
|
||||||
# All API endpoints use the /api prefix
|
# Paths in the OpenAPI spec already include /api prefix where needed
|
||||||
return urljoin(base_url, '/api' + path)
|
return urljoin(base_url, path)
|
||||||
|
|
||||||
# Add url helper to the session
|
# Add url helper to the session
|
||||||
session.get_url = get_url # type: ignore
|
session.get_url = get_url # type: ignore
|
||||||
|
@ -77,12 +77,12 @@ def test_endpoints_exist(all_endpoints: List[Dict[str, Any]]):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("endpoint_path", [
|
@pytest.mark.parametrize("endpoint_path", [
|
||||||
"/", # Root path
|
"/", # Root path (doesn't have /api prefix)
|
||||||
"/prompt", # Get prompt info
|
"/api/prompt", # Get prompt info
|
||||||
"/queue", # Get queue
|
"/api/queue", # Get queue
|
||||||
"/models", # Get model types
|
"/api/models", # Get model types
|
||||||
"/object_info", # Get node info
|
"/api/object_info", # Get node info
|
||||||
"/system_stats" # Get system stats
|
"/api/system_stats" # Get system stats
|
||||||
])
|
])
|
||||||
def test_basic_get_endpoints(require_server, api_client, endpoint_path: str):
|
def test_basic_get_endpoints(require_server, api_client, endpoint_path: str):
|
||||||
"""
|
"""
|
||||||
@ -116,7 +116,7 @@ def test_websocket_endpoint_exists(require_server, base_url: str):
|
|||||||
require_server: Fixture that skips if server is not available
|
require_server: Fixture that skips if server is not available
|
||||||
base_url: Base server URL
|
base_url: Base server URL
|
||||||
"""
|
"""
|
||||||
# WebSocket endpoint uses /api prefix
|
# WebSocket endpoint path from OpenAPI spec
|
||||||
ws_url = urljoin(base_url, "/api/ws")
|
ws_url = urljoin(base_url, "/api/ws")
|
||||||
|
|
||||||
# For WebSocket, we can't use a normal GET request
|
# For WebSocket, we can't use a normal GET request
|
||||||
@ -143,7 +143,7 @@ def test_api_models_folder_endpoint(require_server, api_client):
|
|||||||
api_client: API client fixture
|
api_client: API client fixture
|
||||||
"""
|
"""
|
||||||
# First get available model types
|
# First get available model types
|
||||||
models_url = api_client.get_url("/models") # type: ignore
|
models_url = api_client.get_url("/api/models") # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
models_response = api_client.get(models_url)
|
models_response = api_client.get(models_url)
|
||||||
@ -157,14 +157,14 @@ def test_api_models_folder_endpoint(require_server, api_client):
|
|||||||
|
|
||||||
# Test with the first model type
|
# Test with the first model type
|
||||||
model_type = model_types[0]
|
model_type = model_types[0]
|
||||||
models_folder_url = api_client.get_url(f"/models/{model_type}") # type: ignore
|
models_folder_url = api_client.get_url(f"/api/models/{model_type}") # type: ignore
|
||||||
|
|
||||||
folder_response = api_client.get(models_folder_url)
|
folder_response = api_client.get(models_folder_url)
|
||||||
|
|
||||||
# We're just checking that the endpoint exists
|
# We're just checking that the endpoint exists
|
||||||
assert folder_response.status_code != 404, f"Endpoint /models/{model_type} does not exist"
|
assert folder_response.status_code != 404, f"Endpoint /api/models/{model_type} does not exist"
|
||||||
|
|
||||||
logger.info(f"Endpoint /models/{model_type} exists with status code {folder_response.status_code}")
|
logger.info(f"Endpoint /api/models/{model_type} exists with status code {folder_response.status_code}")
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
pytest.fail(f"Request failed: {str(e)}")
|
pytest.fail(f"Request failed: {str(e)}")
|
||||||
@ -181,7 +181,7 @@ def test_api_object_info_node_endpoint(require_server, api_client):
|
|||||||
api_client: API client fixture
|
api_client: API client fixture
|
||||||
"""
|
"""
|
||||||
# First get available node classes
|
# First get available node classes
|
||||||
objects_url = api_client.get_url("/object_info") # type: ignore
|
objects_url = api_client.get_url("/api/object_info") # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
objects_response = api_client.get(objects_url)
|
objects_response = api_client.get(objects_url)
|
||||||
@ -195,14 +195,14 @@ def test_api_object_info_node_endpoint(require_server, api_client):
|
|||||||
|
|
||||||
# Test with the first node class
|
# Test with the first node class
|
||||||
node_class = next(iter(node_classes.keys()))
|
node_class = next(iter(node_classes.keys()))
|
||||||
node_url = api_client.get_url(f"/object_info/{node_class}") # type: ignore
|
node_url = api_client.get_url(f"/api/object_info/{node_class}") # type: ignore
|
||||||
|
|
||||||
node_response = api_client.get(node_url)
|
node_response = api_client.get(node_url)
|
||||||
|
|
||||||
# We're just checking that the endpoint exists
|
# We're just checking that the endpoint exists
|
||||||
assert node_response.status_code != 404, f"Endpoint /object_info/{node_class} does not exist"
|
assert node_response.status_code != 404, f"Endpoint /api/object_info/{node_class} does not exist"
|
||||||
|
|
||||||
logger.info(f"Endpoint /object_info/{node_class} exists with status code {node_response.status_code}")
|
logger.info(f"Endpoint /api/object_info/{node_class} exists with status code {node_response.status_code}")
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
pytest.fail(f"Request failed: {str(e)}")
|
pytest.fail(f"Request failed: {str(e)}")
|
||||||
|
@ -132,11 +132,11 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("endpoint_path,method", [
|
@pytest.mark.parametrize("endpoint_path,method", [
|
||||||
("/system_stats", "get"),
|
("/api/system_stats", "get"),
|
||||||
("/prompt", "get"),
|
("/api/prompt", "get"),
|
||||||
("/queue", "get"),
|
("/api/queue", "get"),
|
||||||
("/models", "get"),
|
("/api/models", "get"),
|
||||||
("/embeddings", "get")
|
("/api/embeddings", "get")
|
||||||
])
|
])
|
||||||
def test_response_schema_validation(
|
def test_response_schema_validation(
|
||||||
require_server,
|
require_server,
|
||||||
@ -182,7 +182,7 @@ def test_response_schema_validation(
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Special handling for system_stats endpoint
|
# Special handling for system_stats endpoint
|
||||||
if endpoint_path == '/system_stats' and isinstance(response_data, dict):
|
if endpoint_path == '/api/system_stats' and isinstance(response_data, dict):
|
||||||
# Remove null index fields before validation
|
# Remove null index fields before validation
|
||||||
for device in response_data.get('devices', []):
|
for device in response_data.get('devices', []):
|
||||||
if 'index' in device and device['index'] is None:
|
if 'index' in device and device['index'] is None:
|
||||||
@ -217,7 +217,7 @@ def test_system_stats_response(require_server, api_client, api_spec: Dict[str, A
|
|||||||
api_client: API client fixture
|
api_client: API client fixture
|
||||||
api_spec: Loaded OpenAPI spec
|
api_spec: Loaded OpenAPI spec
|
||||||
"""
|
"""
|
||||||
url = api_client.get_url("/system_stats") # type: ignore
|
url = api_client.get_url("/api/system_stats") # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = api_client.get(url)
|
response = api_client.get(url)
|
||||||
@ -259,7 +259,7 @@ def test_system_stats_response(require_server, api_client, api_spec: Dict[str, A
|
|||||||
validation_result = validate_response(
|
validation_result = validate_response(
|
||||||
stats,
|
stats,
|
||||||
api_spec,
|
api_spec,
|
||||||
"/system_stats",
|
"/api/system_stats",
|
||||||
"get"
|
"get"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ def test_system_stats_response(require_server, api_client, api_spec: Dict[str, A
|
|||||||
assert validation_result['valid'], "System stats response does not match schema"
|
assert validation_result['valid'], "System stats response does not match schema"
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
pytest.fail(f"Request to /system_stats failed: {str(e)}")
|
pytest.fail(f"Request to /api/system_stats failed: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
def test_models_listing_response(require_server, api_client, api_spec: Dict[str, Any]):
|
def test_models_listing_response(require_server, api_client, api_spec: Dict[str, Any]):
|
||||||
@ -291,7 +291,7 @@ def test_models_listing_response(require_server, api_client, api_spec: Dict[str,
|
|||||||
api_client: API client fixture
|
api_client: API client fixture
|
||||||
api_spec: Loaded OpenAPI spec
|
api_spec: Loaded OpenAPI spec
|
||||||
"""
|
"""
|
||||||
url = api_client.get_url("/models") # type: ignore
|
url = api_client.get_url("/api/models") # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = api_client.get(url)
|
response = api_client.get(url)
|
||||||
@ -312,7 +312,7 @@ def test_models_listing_response(require_server, api_client, api_spec: Dict[str,
|
|||||||
validation_result = validate_response(
|
validation_result = validate_response(
|
||||||
models,
|
models,
|
||||||
api_spec,
|
api_spec,
|
||||||
"/models",
|
"/api/models",
|
||||||
"get"
|
"get"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ def test_models_listing_response(require_server, api_client, api_spec: Dict[str,
|
|||||||
assert validation_result['valid'], "Models response does not match schema"
|
assert validation_result['valid'], "Models response does not match schema"
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
pytest.fail(f"Request to /models failed: {str(e)}")
|
pytest.fail(f"Request to /api/models failed: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
def test_object_info_response(require_server, api_client, api_spec: Dict[str, Any]):
|
def test_object_info_response(require_server, api_client, api_spec: Dict[str, Any]):
|
||||||
@ -345,7 +345,7 @@ def test_object_info_response(require_server, api_client, api_spec: Dict[str, An
|
|||||||
api_client: API client fixture
|
api_client: API client fixture
|
||||||
api_spec: Loaded OpenAPI spec
|
api_spec: Loaded OpenAPI spec
|
||||||
"""
|
"""
|
||||||
url = api_client.get_url("/object_info") # type: ignore
|
url = api_client.get_url("/api/object_info") # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = api_client.get(url)
|
response = api_client.get(url)
|
||||||
@ -373,7 +373,7 @@ def test_object_info_response(require_server, api_client, api_spec: Dict[str, An
|
|||||||
validation_result = validate_response(
|
validation_result = validate_response(
|
||||||
objects,
|
objects,
|
||||||
api_spec,
|
api_spec,
|
||||||
"/object_info",
|
"/api/object_info",
|
||||||
"get"
|
"get"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -394,7 +394,7 @@ def test_object_info_response(require_server, api_client, api_spec: Dict[str, An
|
|||||||
assert validation_result['valid'], "Object info response does not match schema"
|
assert validation_result['valid'], "Object info response does not match schema"
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
pytest.fail(f"Request to /object_info failed: {str(e)}")
|
pytest.fail(f"Request to /api/object_info failed: {str(e)}")
|
||||||
except (KeyError, StopIteration) as e:
|
except (KeyError, StopIteration) as e:
|
||||||
pytest.fail(f"Failed to process response: {str(e)}")
|
pytest.fail(f"Failed to process response: {str(e)}")
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ def test_queue_response(require_server, api_client, api_spec: Dict[str, Any]):
|
|||||||
api_client: API client fixture
|
api_client: API client fixture
|
||||||
api_spec: Loaded OpenAPI spec
|
api_spec: Loaded OpenAPI spec
|
||||||
"""
|
"""
|
||||||
url = api_client.get_url("/queue") # type: ignore
|
url = api_client.get_url("/api/queue") # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = api_client.get(url)
|
response = api_client.get(url)
|
||||||
@ -430,7 +430,7 @@ def test_queue_response(require_server, api_client, api_spec: Dict[str, Any]):
|
|||||||
validation_result = validate_response(
|
validation_result = validate_response(
|
||||||
queue,
|
queue,
|
||||||
api_spec,
|
api_spec,
|
||||||
"/queue",
|
"/api/queue",
|
||||||
"get"
|
"get"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -61,9 +61,9 @@ def test_workflow_endpoints_exist(api_spec: Dict[str, Any]):
|
|||||||
Args:
|
Args:
|
||||||
api_spec: Loaded OpenAPI spec
|
api_spec: Loaded OpenAPI spec
|
||||||
"""
|
"""
|
||||||
assert '/prompt' in api_spec['paths'], "Spec must define /prompt endpoint"
|
assert '/api/prompt' in api_spec['paths'], "Spec must define /api/prompt endpoint"
|
||||||
assert 'post' in api_spec['paths']['/prompt'], "Spec must define POST /prompt"
|
assert 'post' in api_spec['paths']['/api/prompt'], "Spec must define POST /api/prompt"
|
||||||
assert 'get' in api_spec['paths']['/prompt'], "Spec must define GET /prompt"
|
assert 'get' in api_spec['paths']['/api/prompt'], "Spec must define GET /api/prompt"
|
||||||
|
|
||||||
|
|
||||||
def test_image_endpoints_exist(api_spec: Dict[str, Any]):
|
def test_image_endpoints_exist(api_spec: Dict[str, Any]):
|
||||||
@ -73,8 +73,8 @@ def test_image_endpoints_exist(api_spec: Dict[str, Any]):
|
|||||||
Args:
|
Args:
|
||||||
api_spec: Loaded OpenAPI spec
|
api_spec: Loaded OpenAPI spec
|
||||||
"""
|
"""
|
||||||
assert '/upload/image' in api_spec['paths'], "Spec must define /upload/image endpoint"
|
assert '/api/upload/image' in api_spec['paths'], "Spec must define /api/upload/image endpoint"
|
||||||
assert '/view' in api_spec['paths'], "Spec must define /view endpoint"
|
assert '/api/view' in api_spec['paths'], "Spec must define /api/view endpoint"
|
||||||
|
|
||||||
|
|
||||||
def test_model_endpoints_exist(api_spec: Dict[str, Any]):
|
def test_model_endpoints_exist(api_spec: Dict[str, Any]):
|
||||||
@ -84,8 +84,8 @@ def test_model_endpoints_exist(api_spec: Dict[str, Any]):
|
|||||||
Args:
|
Args:
|
||||||
api_spec: Loaded OpenAPI spec
|
api_spec: Loaded OpenAPI spec
|
||||||
"""
|
"""
|
||||||
assert '/models' in api_spec['paths'], "Spec must define /models endpoint"
|
assert '/api/models' in api_spec['paths'], "Spec must define /api/models endpoint"
|
||||||
assert '/models/{folder}' in api_spec['paths'], "Spec must define /models/{folder} endpoint"
|
assert '/api/models/{folder}' in api_spec['paths'], "Spec must define /api/models/{folder} endpoint"
|
||||||
|
|
||||||
|
|
||||||
def test_operation_ids_are_unique(api_spec: Dict[str, Any]):
|
def test_operation_ids_are_unique(api_spec: Dict[str, Any]):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user