Coding
PromptBeginner5 minmarkdown
Markdown Converter
Agent skill for markdown-converter
7
This directory contains the API layer of the test framework template, demonstrating REST API patterns, request/response handling, and API testing strategies.
Sign in to like and favorite skills
This directory contains the API layer of the test framework template, demonstrating REST API patterns, request/response handling, and API testing strategies.
Standard response format for all API endpoints:
class APIResponse: """Standard API response format for consistent client interaction.""" def __init__(self, status_code: int, data: Any = None, message: str = ""): self.status_code = status_code self.data = data self.message = message def to_dict(self) -> Dict[str, Any]: """Convert response to dictionary format.""" return { 'status_code': self.status_code, 'data': self.data, 'message': self.message, 'timestamp': datetime.now().isoformat() }
RESTful API for user management operations:
class UserAPI: """User management API endpoints.""" def __init__(self, user_service: Optional[UserService] = None): """Initialize with optional user service dependency.""" self.user_service = user_service or UserService() def create_user(self, username: str, email: str, password: str) -> APIResponse: """ Create a new user. Args: username: Unique username email: User email address password: User password Returns: APIResponse with status 201 on success, 400 on validation error """ try: user = self.user_service.create_user(username, email, password) return APIResponse( status_code=201, data=user.to_dict(), message="User created successfully" ) except ValueError as e: return APIResponse( status_code=400, data=None, message=str(e) ) except Exception as e: return APIResponse( status_code=500, data=None, message="Internal server error" )
Test individual endpoints in isolation:
class TestUserAPI: """Unit tests for UserAPI endpoints.""" def test_create_user_success(self, mock_user_service): """Test successful user creation.""" # Arrange mock_user = User(1, "testuser", "[email protected]", "hashedpass") mock_user_service.create_user.return_value = mock_user api = UserAPI(mock_user_service) # Act response = api.create_user("testuser", "[email protected]", "password123") # Assert assert response.status_code == 201 assert response.data['username'] == "testuser" assert 'password' not in response.data mock_user_service.create_user.assert_called_once_with( "testuser", "[email protected]", "password123" ) def test_create_user_validation_error(self, mock_user_service): """Test user creation with validation error.""" # Arrange mock_user_service.create_user.side_effect = ValueError("Username already exists") api = UserAPI(mock_user_service) # Act response = api.create_user("duplicate", "[email protected]", "password123") # Assert assert response.status_code == 400 assert "Username already exists" in response.message assert response.data is None
Test API endpoints with real service layer:
class TestUserAPIIntegration: """Integration tests for UserAPI with UserService.""" def test_complete_user_workflow(self, user_api): """Test complete user CRUD workflow through API.""" # Create user create_response = user_api.create_user("workflow", "[email protected]", "password123") assert create_response.status_code == 201 user_id = create_response.data['id'] # Get user get_response = user_api.get_user(user_id) assert get_response.status_code == 200 assert get_response.data['username'] == "workflow" # Update user update_response = user_api.update_user(user_id, username="updated_workflow") assert update_response.status_code == 200 assert update_response.data['username'] == "updated_workflow" # Delete user delete_response = user_api.delete_user(user_id) assert delete_response.status_code == 204 # Verify deletion get_deleted_response = user_api.get_user(user_id) assert get_deleted_response.status_code == 404
def _handle_error(self, error: Exception) -> APIResponse: """Convert exceptions to appropriate API responses.""" if isinstance(error, ValueError): return APIResponse(400, None, str(error)) elif isinstance(error, UserNotFoundError): return APIResponse(404, None, "User not found") elif isinstance(error, DuplicateUserError): return APIResponse(409, None, "User already exists") else: # Log the error for debugging logger.error(f"Unexpected error: {error}") return APIResponse(500, None, "Internal server error")
def _validate_create_user_request(self, username: str, email: str, password: str) -> List[str]: """Validate user creation request parameters.""" errors = [] if not username or not username.strip(): errors.append("Username is required") elif len(username) < 3: errors.append("Username must be at least 3 characters") if not email or not email.strip(): errors.append("Email is required") elif '@' not in email: errors.append("Email must be valid") if not password or len(password) < 6: errors.append("Password must be at least 6 characters") return errors
def _sanitize_user_data(self, user: User) -> Dict[str, Any]: """Remove sensitive data from user object.""" user_dict = user.to_dict() # Remove sensitive fields user_dict.pop('password_hash', None) user_dict.pop('password', None) return user_dict
def authenticate(self, username: str, password: str) -> APIResponse: """ Authenticate user credentials. Args: username: Username or email password: User password Returns: APIResponse with user data on success, 401 on failure """ try: user = self.user_service.authenticate_user(username, password) if user: return APIResponse( status_code=200, data=self._sanitize_user_data(user), message="Authentication successful" ) else: return APIResponse( status_code=401, data=None, message="Invalid credentials" ) except Exception as e: return APIResponse( status_code=500, data=None, message="Authentication service error" )
def test_authenticate_success(self, user_api, user_service): """Test successful authentication.""" # Create user first user_service.create_user("testuser", "[email protected]", "password123") # Test authentication response = user_api.authenticate("testuser", "password123") assert response.status_code == 200 assert response.data['username'] == "testuser" assert 'password' not in response.data def test_authenticate_invalid_credentials(self, user_api): """Test authentication with invalid credentials.""" response = user_api.authenticate("nonexistent", "wrongpassword") assert response.status_code == 401 assert "Invalid credentials" in response.message
def get_users(self, page: int = 1, limit: int = 10, search: str = None) -> APIResponse: """ Get list of users with pagination and optional search. Args: page: Page number (1-based) limit: Number of users per page (max 100) search: Optional search term for username/email Returns: APIResponse with user list and pagination info Response Format: { "status_code": 200, "data": { "users": [...], "pagination": { "page": 1, "limit": 10, "total": 50, "pages": 5 } }, "message": "Users retrieved successfully" } """
def get_users(self, page: int = 1, limit: int = 10) -> APIResponse: """Get paginated list of users.""" try: # Validate pagination parameters page = max(1, page) limit = min(max(1, limit), 100) # Cap at 100 items per page offset = (page - 1) * limit users, total = self.user_service.get_users_paginated(offset, limit) return APIResponse( status_code=200, data={ 'users': [self._sanitize_user_data(user) for user in users], 'pagination': { 'page': page, 'limit': limit, 'total': total, 'pages': (total + limit - 1) // limit } }, message="Users retrieved successfully" ) except Exception as e: return APIResponse(500, None, "Error retrieving users")
from functools import lru_cache @lru_cache(maxsize=128) def get_user_cached(self, user_id: int) -> APIResponse: """Get user with caching for improved performance.""" # Implementation would include cache invalidation logic pass
@responses.activate def test_external_api_integration(): """Test integration with external APIs using responses.""" responses.add( responses.POST, 'https://external-api.com/validate', json={'valid': True}, status=200 ) # Test code that calls external API result = api.validate_external_data({'email': '[email protected]'}) assert result.status_code == 200
This API layer demonstrates professional REST API development practices with comprehensive testing strategies.