The @chute.cord() decorator is used to create HTTP API endpoints in Chutes applications. This reference covers all parameters, patterns, and best practices for building robust API endpoints.
The URL path where the endpoint will be accessible.
Format Rules:
Must start with /
Can include path parameters with {parameter_name} syntax
Should follow REST conventions
Case-sensitive
Examples:
# Simple path@chute.cord(public_api_path="/generate")# Path with parameter@chute.cord(public_api_path="/users/{user_id}")# Nested resource@chute.cord(public_api_path="/models/{model_id}/generate")# Multiple parameters@chute.cord(public_api_path="/users/{user_id}/files/{file_id}")
Best Practices:
Use kebab-case for multi-word paths: /generate-text
Use nouns for resources: /users, /models
Use verbs for actions: /generate, /process
Keep paths concise but descriptive
Optional Parameters
method: str = "POST"
The HTTP method for the endpoint.
Supported Methods:
GET - Retrieve data
POST - Create or process data
PUT - Update existing data
DELETE - Remove data
PATCH - Partial updates
HEAD - Get headers only
OPTIONS - Get allowed methods
Examples:
# GET for data retrieval@chute.cord(public_api_path="/models", method="GET")asyncdeflist_models(self):
return {"models": ["gpt-3.5", "gpt-4"]}
# POST for data processing@chute.cord(public_api_path="/generate", method="POST")asyncdefgenerate_text(self, prompt: str):
returnawaitself.model.generate(prompt)
# PUT for updates@chute.cord(public_api_path="/config", method="PUT")asyncdefupdate_config(self, config: dict):
self.config.update(config)
return {"status": "updated"}
# DELETE for removal@chute.cord(public_api_path="/cache", method="DELETE")asyncdefclear_cache(self):
self.cache.clear()
return {"status": "cache cleared"}
Method Selection Guidelines:
Use GET for read-only operations
Use POST for AI generation/processing
Use PUT for complete resource updates
Use PATCH for partial updates
Use DELETE for resource removal
input_schema: Optional[Type[BaseModel]] = None
Pydantic model for input validation and documentation.
Benefits:
Automatic input validation
Auto-generated API documentation
Type safety
Error handling
Basic Example:
from pydantic import BaseModel, Field
classTextGenerationInput(BaseModel):
prompt: str = Field(..., description="Text prompt for generation")
max_tokens: int = Field(100, ge=1, le=2000, description="Maximum tokens to generate")
temperature: float = Field(0.7, ge=0.0, le=2.0, description="Sampling temperature")
@chute.cord(
public_api_path="/generate",
method="POST",
input_schema=TextGenerationInput
)asyncdefgenerate_text(self, input_data: TextGenerationInput):
returnawaitself.model.generate(
input_data.prompt,
max_tokens=input_data.max_tokens,
temperature=input_data.temperature
)
Advanced Schema Example:
from typing importOptional, List, Literalfrom pydantic import validator
classAdvancedGenerationInput(BaseModel):
prompt: str = Field(..., min_length=1, max_length=10000)
model_type: Literal["gpt-3.5", "gpt-4", "claude"] = Field("gpt-3.5")
max_tokens: int = Field(100, ge=1, le=4000)
temperature: float = Field(0.7, ge=0.0, le=2.0)
top_p: Optional[float] = Field(None, ge=0.0, le=1.0)
stop_sequences: Optional[List[str]] = Field(None, max_items=4)
seed: Optional[int] = Field(None, ge=0)
@validator('stop_sequences')defvalidate_stop_sequences(cls, v):
if v andany(len(seq) > 10for seq in v):
raise ValueError('Stop sequences must be 10 characters or less')
return v
classConfig:
schema_extra = {
"example": {
"prompt": "Write a haiku about AI",
"model_type": "gpt-4",
"max_tokens": 50,
"temperature": 0.8,
"stop_sequences": ["\n\n"]
}
}
@chute.cord(
public_api_path="/advanced_generate",
input_schema=AdvancedGenerationInput
)asyncdefadvanced_generate(self, params: AdvancedGenerationInput):
returnawaitself.model.generate(
prompt=params.prompt,
model=params.model_type,
max_tokens=params.max_tokens,
temperature=params.temperature,
top_p=params.top_p,
stop=params.stop_sequences,
seed=params.seed
)
output_schema: Optional[Type[BaseModel]] = None
Pydantic model for output validation and documentation.
@chute.cord(
public_api_path="/generate",
output_content_type="application/json"# Optional, this is default)asyncdefgenerate_json(self, prompt: str):
result = awaitself.model.generate(prompt)
return {"generated_text": result}
# Basic function with primitive parameters@chute.cord(public_api_path="/simple")asyncdefsimple_endpoint(self, text: str, number: int = 10):
return {"text": text, "number": number}
# Function with optional parameters@chute.cord(public_api_path="/optional")asyncdefoptional_params(
self,
required_param: str,
optional_param: Optional[str] = None,
default_param: int = 100):
return {
"required": required_param,
"optional": optional_param,
"default": default_param
}
Schema-Based Functions
# Function with input schema@chute.cord(
public_api_path="/with_schema",
input_schema=MyInputSchema
)asyncdefschema_endpoint(self, input_data: MyInputSchema):
returnawaitself.process(input_data)
# Function with both input and output schemas@chute.cord(
public_api_path="/full_schema",
input_schema=MyInputSchema,
output_schema=MyOutputSchema
)asyncdeffull_schema_endpoint(self, input_data: MyInputSchema) -> MyOutputSchema:
result = awaitself.process(input_data)
return MyOutputSchema(**result)
Path Parameter Functions
# Single path parameter@chute.cord(public_api_path="/users/{user_id}")asyncdefget_user(self, user_id: str):
return {"user_id": user_id}
# Multiple path parameters@chute.cord(public_api_path="/users/{user_id}/files/{file_id}")asyncdefget_user_file(self, user_id: str, file_id: str):
return {"user_id": user_id, "file_id": file_id}
# Path parameters with body@chute.cord(
public_api_path="/users/{user_id}/generate",
input_schema=GenerationInput
)asyncdefgenerate_for_user(self, user_id: str, params: GenerationInput):
# Use user_id for personalization
personalized_prompt = f"For user {user_id}: {params.prompt}"returnawaitself.model.generate(personalized_prompt)
Query Parameter Functions
from fastapi import Query
@chute.cord(public_api_path="/search", method="GET")asyncdefsearch_endpoint(
self,
query: str = Query(..., description="Search query"),
limit: int = Query(10, ge=1, le=100, description="Number of results"),
offset: int = Query(0, ge=0, description="Result offset"),
sort_by: str = Query("relevance", description="Sort criteria")
):
return {
"query": query,
"limit": limit,
"offset": offset,
"sort_by": sort_by,
"results": [] # Your search results here
}
File Upload Functions
from fastapi import File, UploadFile
@chute.cord(public_api_path="/upload", method="POST")asyncdefupload_file(self, file: UploadFile = File(...)):
# Read file content
content = await file.read()
# Process file
result = awaitself.process_file(content, file.filename)
return {
"filename": file.filename,
"size": len(content),
"content_type": file.content_type,
"result": result
}
# Multiple file upload@chute.cord(public_api_path="/upload_multiple", method="POST")asyncdefupload_multiple_files(self, files: List[UploadFile] = File(...)):
results = []
for file in files:
content = await file.read()
result = awaitself.process_file(content, file.filename)
results.append({
"filename": file.filename,
"size": len(content),
"result": result
})
return {"files_processed": len(results), "results": results}
Advanced Patterns
Error Handling
from fastapi import HTTPException
@chute.cord(public_api_path="/generate_with_errors")asyncdefgenerate_with_error_handling(self, prompt: str):
try:
# Validate inputifnot prompt.strip():
raise HTTPException(
status_code=400,
detail="Prompt cannot be empty"
)
iflen(prompt) > 10000:
raise HTTPException(
status_code=400,
detail="Prompt too long (max 10,000 characters)"
)
# Process
result = awaitself.model.generate(prompt)
# Validate outputifnot result:
raise HTTPException(
status_code=500,
detail="Model failed to generate output"
)
return {"generated_text": result}
except HTTPException:
raise# Re-raise HTTP exceptionsexcept Exception as e:
# Log the errorself.logger.error(f"Generation failed: {e}")
# Return user-friendly errorraise HTTPException(
status_code=500,
detail="Internal server error during text generation"
)
Authentication and Authorization
from fastapi import Depends, Request, HTTPException
asyncdefverify_api_key(request: Request):
"""Dependency for API key verification."""
api_key = request.headers.get("X-API-Key")
ifnot api_key:
raise HTTPException(
status_code=401,
detail="API key required"
)
# Validate API key (implement your logic)ifnot is_valid_api_key(api_key):
raise HTTPException(
status_code=401,
detail="Invalid API key"
)
return api_key
@chute.cord(public_api_path="/protected_generate")asyncdefprotected_generate(
self,
prompt: str,
api_key: str = Depends(verify_api_key)
):
"""Protected endpoint requiring API key."""# Log usage for the API keyself.logger.info(f"Generation request from API key: {api_key[:8]}...")
result = awaitself.model.generate(prompt)
return {"generated_text": result}
Rate Limiting
import time
from collections import defaultdict
from fastapi import Request, HTTPException
classRateLimiter:
def__init__(self):
self.requests = defaultdict(list)
self.window_size = 60# 1 minuteself.max_requests = 100defis_allowed(self, identifier: str) -> bool:
now = time.time()
window_start = now - self.window_size
# Clean old requestsself.requests[identifier] = [
req_time for req_time inself.requests[identifier]
if req_time > window_start
]
# Check limitiflen(self.requests[identifier]) >= self.max_requests:
returnFalse# Add current requestself.requests[identifier].append(now)
returnTrue# Initialize rate limiter
rate_limiter = RateLimiter()
asyncdefcheck_rate_limit(request: Request):
"""Rate limiting dependency."""
identifier = request.client.host # Use IP addressifnot rate_limiter.is_allowed(identifier):
raise HTTPException(
status_code=429,
detail="Rate limit exceeded"
)
@chute.cord(public_api_path="/rate_limited_generate")asyncdefrate_limited_generate(
self,
prompt: str,
rate_limit_check: None = Depends(check_rate_limit)
):
returnawaitself.model.generate(prompt)
# GET for data retrieval@chute.cord(public_api_path="/models", method="GET")# POST for data processing@chute.cord(public_api_path="/generate", method="POST")# PUT for full updates@chute.cord(public_api_path="/config", method="PUT")