"""Mock server generator for Prism/OpenAPI mock support.""" import json from pathlib import Path from typing import Any, Dict, List, Optional from ..core import SpecParser class MockServerGenerator: """Generate Prism/OpenAPI mock server configurations.""" DEFAULT_PORT = 4010 DEFAULT_HOST = "0.0.0.0" def __init__( self, spec_parser: SpecParser, output_dir: str = ".", ): """Initialize the mock server generator. Args: spec_parser: The OpenAPI specification parser. output_dir: Directory for generated configuration files. """ self.spec_parser = spec_parser self.output_dir = Path(output_dir) def generate( self, prism_config: bool = True, docker_compose: bool = True, dockerfile: bool = True, ) -> List[Path]: """Generate mock server configuration files. Args: prism_config: Whether to generate prism-config.json. docker_compose: Whether to generate docker-compose.yml. dockerfile: Whether to generate Dockerfile. Returns: List of generated file paths. """ self.output_dir.mkdir(parents=True, exist_ok=True) generated_files = [] if prism_config: generated_files.append(self.generate_prism_config()) if docker_compose: generated_files.append(self.generate_docker_compose()) if dockerfile: generated_files.append(self.generate_dockerfile()) return generated_files def generate_prism_config(self, output_file: Optional[str] = None) -> Path: """Generate Prism mock server configuration. Args: output_file: Optional output file path. Returns: Path to the generated file. """ if output_file: output_path = Path(output_file) else: output_path = self.output_dir / "prism-config.json" config = { "mock": { "host": self.DEFAULT_HOST, "port": self.DEFAULT_PORT, "cors": { "enabled": True, "allowOrigin": "*", "allowMethods": ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"], "allowHeaders": ["Content-Type", "Authorization", "X-API-Key"], }, "Validation": { "request": True, "response": True, }, }, "logging": { "level": "info", "format": "json", }, } output_path.write_text(json.dumps(config, indent=2)) return output_path def generate_docker_compose(self, output_file: Optional[str] = None) -> Path: """Generate Docker Compose configuration for mock server. Args: output_file: Optional output file path. Returns: Path to the generated file. """ if output_file: output_path = Path(output_file) else: output_path = self.output_dir / "docker-compose.yml" spec_info = self.spec_parser.get_info() compose_content = f'''version: '3.8' services: mock-server: image: stoplight/prism:latest container_name: "{spec_info['title']}-mock-server" command: > mock --spec /app/openapi.yaml --port {self.DEFAULT_PORT} --host {self.DEFAULT_HOST} ports: - "{self.DEFAULT_PORT}:{self.DEFAULT_PORT}" volumes: - ./:/app restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", f"http://localhost:{self.DEFAULT_PORT}/health"] interval: 30s timeout: 10s retries: 3 mock-server-https: image: stoplight/prism:latest container_name: "{spec_info['title']}-mock-server-https" command: > mock --spec /app/openapi.yaml --port {self.DEFAULT_PORT + 1} --host {self.DEFAULT_HOST} ports: - "{self.DEFAULT_PORT + 1}:{self.DEFAULT_PORT + 1}" volumes: - ./:/app restart: unless-stopped ''' output_path.write_text(compose_content) return output_path def generate_dockerfile(self, output_file: Optional[str] = None) -> Path: """Generate Dockerfile for mock server. Args: output_file: Optional output file path. Returns: Path to the generated file. """ if output_file: output_path = Path(output_file) else: output_path = self.output_dir / "Dockerfile" spec_info = self.spec_parser.get_info() dockerfile_content = f'''FROM stoplight/prism:latest LABEL maintainer="developer@example.com" LABEL description="Mock server for {spec_info['title']} API" WORKDIR /app COPY openapi.yaml . EXPOSE {self.DEFAULT_PORT} CMD ["mock", "--spec", "openapi.yaml", "--port", "{self.DEFAULT_PORT}", "--host", "0.0.0.0"] ''' output_path.write_text(dockerfile_content) return output_path def generate_start_script(self, output_file: Optional[str] = None) -> Path: """Generate shell script to start mock server. Args: output_file: Optional output file path. Returns: Path to the generated file. """ if output_file: output_path = Path(output_file) else: output_path = self.output_dir / "start-mock-server.sh" script_content = f'''#!/bin/bash set -e SCRIPT_DIR="$(cd "$(dirname "${{BASH_SOURCE[0]}}")" && pwd)" cd "$SCRIPT_DIR" PORT={self.DEFAULT_PORT} HOST="0.0.0.0" echo "Starting mock server for API..." echo "Mock server will be available at: http://localhost:$PORT" docker compose up -d mock-server echo "Mock server started successfully!" echo "To stop: docker compose down" ''' output_path.write_text(script_content) output_path.chmod(0o755) return output_path def generate_health_check(self) -> Path: """Generate health check endpoint configuration. Returns: Path to the generated file. """ output_path = self.output_dir / "health-check.json" spec_info = self.spec_parser.get_info() health_check = { "openapi": self.spec_parser.version, "info": { "title": f"{spec_info['title']} - Health Check", "version": spec_info["version"], "description": "Health check endpoint for the mock server", }, "paths": { "/health": { "get": { "summary": "Health check endpoint", "description": "Returns the health status of the mock server", "operationId": "healthCheck", "responses": { "200": { "description": "Mock server is healthy", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": ["healthy"], }, "api": { "type": "string", }, "version": { "type": "string", }, }, }, } }, } }, } } }, } output_path.write_text(json.dumps(health_check, indent=2)) return output_path