feat(schemas): T23 add Pydantic API key schemas
- Add ApiKeyCreate schema with OpenRouter key format validation - Add ApiKeyUpdate schema for partial updates - Add ApiKeyResponse schema (excludes key value for security) - Add ApiKeyListResponse schema for pagination - Export schemas from __init__.py - 100% coverage on new module (23 tests) Refs: T23
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
"""Schemas package for OpenRouter Monitor."""
|
||||
from openrouter_monitor.schemas.api_key import (
|
||||
ApiKeyCreate,
|
||||
ApiKeyListResponse,
|
||||
ApiKeyResponse,
|
||||
ApiKeyUpdate,
|
||||
)
|
||||
from openrouter_monitor.schemas.auth import (
|
||||
TokenData,
|
||||
TokenResponse,
|
||||
@@ -13,4 +19,8 @@ __all__ = [
|
||||
"UserResponse",
|
||||
"TokenResponse",
|
||||
"TokenData",
|
||||
"ApiKeyCreate",
|
||||
"ApiKeyUpdate",
|
||||
"ApiKeyResponse",
|
||||
"ApiKeyListResponse",
|
||||
]
|
||||
|
||||
138
src/openrouter_monitor/schemas/api_key.py
Normal file
138
src/openrouter_monitor/schemas/api_key.py
Normal file
@@ -0,0 +1,138 @@
|
||||
"""API Key Pydantic schemas.
|
||||
|
||||
T23: Pydantic schemas for API key management.
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
|
||||
class ApiKeyCreate(BaseModel):
|
||||
"""Schema for creating a new API key.
|
||||
|
||||
Attributes:
|
||||
name: Human-readable name for the key (1-100 chars)
|
||||
key: OpenRouter API key (must start with 'sk-or-v1-')
|
||||
"""
|
||||
|
||||
name: str = Field(
|
||||
...,
|
||||
min_length=1,
|
||||
max_length=100,
|
||||
description="Human-readable name for the API key",
|
||||
examples=["Production Key"]
|
||||
)
|
||||
key: str = Field(
|
||||
...,
|
||||
description="OpenRouter API key",
|
||||
examples=["sk-or-v1-abc123..."]
|
||||
)
|
||||
|
||||
@field_validator('key')
|
||||
@classmethod
|
||||
def validate_key_format(cls, v: str) -> str:
|
||||
"""Validate OpenRouter API key format.
|
||||
|
||||
Args:
|
||||
v: The API key value to validate
|
||||
|
||||
Returns:
|
||||
The API key if valid
|
||||
|
||||
Raises:
|
||||
ValueError: If key doesn't start with 'sk-or-v1-'
|
||||
"""
|
||||
if not v or not v.strip():
|
||||
raise ValueError("API key cannot be empty")
|
||||
|
||||
if not v.startswith('sk-or-v1-'):
|
||||
raise ValueError("API key must start with 'sk-or-v1-'")
|
||||
|
||||
return v
|
||||
|
||||
|
||||
class ApiKeyUpdate(BaseModel):
|
||||
"""Schema for updating an existing API key.
|
||||
|
||||
All fields are optional - only provided fields will be updated.
|
||||
|
||||
Attributes:
|
||||
name: New name for the key (optional, 1-100 chars)
|
||||
is_active: Whether the key should be active (optional)
|
||||
"""
|
||||
|
||||
name: Optional[str] = Field(
|
||||
default=None,
|
||||
min_length=1,
|
||||
max_length=100,
|
||||
description="New name for the API key",
|
||||
examples=["Updated Key Name"]
|
||||
)
|
||||
is_active: Optional[bool] = Field(
|
||||
default=None,
|
||||
description="Whether the key should be active",
|
||||
examples=[True, False]
|
||||
)
|
||||
|
||||
|
||||
class ApiKeyResponse(BaseModel):
|
||||
"""Schema for API key response (returned to client).
|
||||
|
||||
Note: The actual API key value is NEVER included in responses
|
||||
for security reasons.
|
||||
|
||||
Attributes:
|
||||
id: API key ID
|
||||
name: API key name
|
||||
is_active: Whether the key is active
|
||||
created_at: When the key was created
|
||||
last_used_at: When the key was last used (None if never used)
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int = Field(
|
||||
...,
|
||||
description="API key ID",
|
||||
examples=[1]
|
||||
)
|
||||
name: str = Field(
|
||||
...,
|
||||
description="API key name",
|
||||
examples=["Production Key"]
|
||||
)
|
||||
is_active: bool = Field(
|
||||
...,
|
||||
description="Whether the key is active",
|
||||
examples=[True]
|
||||
)
|
||||
created_at: datetime = Field(
|
||||
...,
|
||||
description="When the key was created",
|
||||
examples=["2024-01-01T12:00:00"]
|
||||
)
|
||||
last_used_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
description="When the key was last used",
|
||||
examples=["2024-01-02T15:30:00"]
|
||||
)
|
||||
|
||||
|
||||
class ApiKeyListResponse(BaseModel):
|
||||
"""Schema for paginated list of API keys.
|
||||
|
||||
Attributes:
|
||||
items: List of API key responses
|
||||
total: Total number of keys (for pagination)
|
||||
"""
|
||||
|
||||
items: List[ApiKeyResponse] = Field(
|
||||
...,
|
||||
description="List of API keys"
|
||||
)
|
||||
total: int = Field(
|
||||
...,
|
||||
description="Total number of API keys",
|
||||
examples=[10]
|
||||
)
|
||||
Reference in New Issue
Block a user