# API Service Example

This example demonstrates deploying a RESTful API service with database connectivity, comprehensive monitoring, and production-ready configuration.

## Use Case

- RESTful API service (Node.js, Python, Java, Go, etc.)
- Database connectivity with secrets management
- Health checks and metrics exposure
- Auto-scaling based on resource usage
- Production-ready security and observability

## Configuration

```yaml
# API Service Configuration
# Deploy with: helm install my-api drunk-charts/drunk-app -f api-service.yaml

# Application configuration
global:
  image: "mycompany/api-service"
  tag: "v1.2.3"
  imagePullPolicy: "IfNotPresent"
  
  # Image pull secret for private registry
  imagePullSecret: "registry-credentials"

# Deployment configuration
deployment:
  enabled: true
  replicaCount: 3
  
  # API typically runs on port 3000 or 8080
  ports:
    http: 3000
    metrics: 9090  # Prometheus metrics endpoint
  
  # Health check endpoints
  liveness: "/health/live"
  readiness: "/health/ready"
  
  # Custom probe configuration
  livenessProbe:
    httpGet:
      path: "/health/live"
      port: 3000
    initialDelaySeconds: 30
    periodSeconds: 10
    timeoutSeconds: 5
    failureThreshold: 3
  
  readinessProbe:
    httpGet:
      path: "/health/ready"
      port: 3000
    initialDelaySeconds: 5
    periodSeconds: 5
    timeoutSeconds: 3
    failureThreshold: 3

# Environment variables
env:
  NODE_ENV: "production"
  LOG_LEVEL: "info"
  PORT: "3000"
  METRICS_PORT: "9090"
  # Database connection will come from secrets

# Application secrets
secrets:
  DATABASE_PASSWORD: "your-secure-database-password"
  JWT_SECRET: "your-jwt-signing-secret"
  API_KEY: "external-service-api-key"
  REDIS_PASSWORD: "redis-connection-password"

# External secrets (from other charts/services)
secretFrom:
  - "database-credentials"
  - "external-api-keys"

# Configuration files
configMap:
  config.json: |
    {
      "database": {
        "host": "postgres-service.database.svc.cluster.local",
        "port": 5432,
        "name": "api_db",
        "ssl": true,
        "pool": {
          "min": 2,
          "max": 10
        }
      },
      "redis": {
        "host": "redis-service.cache.svc.cluster.local",
        "port": 6379
      },
      "features": {
        "authentication": true,
        "rateLimit": true,
        "cors": true
      }
    }
  
  logging.conf: |
    level=info
    format=json
    output=stdout

# Service configuration
service:
  type: "ClusterIP"
  ports:
    - name: "http"
      port: 80
      targetPort: 3000
    - name: "metrics"
      port: 9090
      targetPort: 9090

# External access
ingress:
  enabled: true
  className: "nginx"
  annotations:
    # Rate limiting
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/rate-limit-window: "1m"
    
    # CORS headers
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
    
    # SSL and security
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    
    # Request size limits
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
  
  hosts:
    - host: "api.example.com"
      paths:
        - path: "/api/v1"
          pathType: "Prefix"
          port: 80
  
  tls:
    - secretName: "api-tls-cert"
      hosts:
        - "api.example.com"

# Resource configuration for production workload
resources:
  requests:
    cpu: "200m"
    memory: "256Mi"
  limits:
    cpu: "1000m"
    memory: "512Mi"

# Horizontal Pod Autoscaler
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80
  
  # Custom scaling behavior
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: "Percent"
          value: 10
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: "Percent"
          value: 50
          periodSeconds: 60

# Security configuration
podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  runAsGroup: 1000
  fsGroup: 1000

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL

# Service account for cloud integrations
serviceAccount:
  create: true
  name: "api-service-account"
  annotations:
    # AWS IAM role annotation (if using AWS)
    eks.amazonaws.com/role-arn: "arn:aws:iam::ACCOUNT:role/api-service-role"
    # Azure managed identity (if using Azure)
    azure.workload.identity/client-id: "your-client-id"

# Storage for logs and temporary files
volumes:
  # Temporary storage (required for read-only root filesystem)
  tmp:
    mountPath: "/tmp"
    emptyDir: true
    size: "1Gi"
  
  # Application logs
  logs:
    mountPath: "/app/logs"
    emptyDir: true
    size: "2Gi"
  
  # Optional: Persistent storage for file uploads
  uploads:
    mountPath: "/app/uploads"
    size: "10Gi"
    storageClass: "fast-ssd"
    accessMode: "ReadWriteOnce"

# Node scheduling preferences
nodeSelector:
  node-type: "api-servers"

tolerations:
  - key: "api-workload"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

affinity:
  # Spread pods across availability zones
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
              - key: "app.kubernetes.io/name"
                operator: "In"
                values: ["drunk-app"]
          topologyKey: "failure-domain.beta.kubernetes.io/zone"

# Optional: Background job for API (e.g., cleanup tasks)
cronJobs:
  - name: "cleanup-expired-sessions"
    schedule: "0 2 * * *"  # Daily at 2 AM
    command: ["node"]
    args: ["scripts/cleanup-sessions.js"]
    restartPolicy: "OnFailure"
    concurrencyPolicy: "Forbid"
    
  - name: "generate-reports"
    schedule: "0 1 * * 1"  # Weekly on Monday at 1 AM
    command: ["node"]
    args: ["scripts/weekly-report.js"]
    restartPolicy: "OnFailure"
```

## Deployment Steps

1. **Prepare your environment**:
   ```bash
   # Create namespace
   kubectl create namespace api-service
   
   # Create registry secret (if using private registry)
   kubectl create secret docker-registry registry-credentials \
     --docker-server=myregistry.com \
     --docker-username=myuser \
     --docker-password=mypassword \
     --docker-email=me@example.com \
     -n api-service
   ```

2. **Deploy supporting services** (if needed):
   ```bash
   # Deploy PostgreSQL (example)
   helm install postgres bitnami/postgresql \
     --set auth.postgresPassword=secretpassword \
     --set auth.database=api_db \
     -n database
   
   # Deploy Redis (example)
   helm install redis bitnami/redis \
     --set auth.password=redispassword \
     -n cache
   ```

3. **Customize and deploy the API**:
   ```bash
   # Save configuration
   curl -o api-service.yaml https://raw.githubusercontent.com/baoduy/drunk.charts/main/docs/examples/api-service.yaml
   
   # Edit configuration
   nano api-service.yaml
   
   # Deploy
   helm install my-api drunk-charts/drunk-app \
     -f api-service.yaml \
     -n api-service
   ```

4. **Verify deployment**:
   ```bash
   # Check all resources
   kubectl get all -n api-service
   
   # Check API health
   kubectl port-forward svc/my-api-drunk-app 8080:80 -n api-service
   curl http://localhost:8080/api/v1/health/live
   ```

## Database Integration Patterns

### PostgreSQL with Connection Pool

```yaml
# In secrets
secrets:
  DATABASE_URL: "postgresql://user:password@postgres-service.database.svc.cluster.local:5432/api_db?sslmode=require"

# In configMap
configMap:
  database.json: |
    {
      "connection": {
        "pool": {
          "min": 2,
          "max": 10,
          "acquireTimeoutMillis": 60000,
          "createTimeoutMillis": 30000,
          "destroyTimeoutMillis": 5000,
          "idleTimeoutMillis": 30000
        }
      }
    }
```

### MongoDB Integration

```yaml
secrets:
  MONGODB_URI: "mongodb://user:password@mongo-service.database.svc.cluster.local:27017/api_db?authSource=admin"

configMap:
  mongodb.conf: |
    maxPoolSize=10
    minPoolSize=2
    maxIdleTimeMS=30000
    serverSelectionTimeoutMS=5000
```

## Monitoring and Observability

### Prometheus Integration

```yaml
deployment:
  ports:
    metrics: 9090
  podAnnotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "9090"
    prometheus.io/path: "/metrics"

# ServiceMonitor for Prometheus Operator
# (This would be a separate resource)
```

### Logging Configuration

```yaml
env:
  LOG_FORMAT: "json"
  LOG_LEVEL: "info"
  LOG_OUTPUT: "stdout"

# Fluentd/Fluent Bit annotations
deployment:
  podAnnotations:
    fluentbit.io/parser: "json"
    fluentbit.io/exclude: "false"
```

### Tracing Setup

```yaml
env:
  JAEGER_AGENT_HOST: "jaeger-agent.tracing.svc.cluster.local"
  JAEGER_AGENT_PORT: "6832"
  TRACING_SAMPLE_RATE: "0.1"
```

## Security Best Practices

### Network Policies

```yaml
# Would require a separate NetworkPolicy resource
deployment:
  podAnnotations:
    # Label for network policy selection
    network-policy: "api-service-policy"
```

### Secret Management with Azure Key Vault

```yaml
secretProvider:
  enabled: true
  name: "api-keyvault"
  tenantId: "your-tenant-id"
  vaultName: "your-key-vault"
  useWorkloadIdentity: true
  objects:
    - objectName: "database-password"
      objectType: "secret"
    - objectName: "jwt-secret"
      objectType: "secret"
    - objectName: "api-certificate"
      objectType: "cert"
  secretObjects:
    - secretName: "api-secrets"
      type: "Opaque"
      data:
        - key: "DATABASE_PASSWORD"
          objectName: "database-password"
        - key: "JWT_SECRET"
          objectName: "jwt-secret"
```

## Performance Tuning

### JVM Applications (Java/Scala)

```yaml
env:
  JAVA_OPTS: "-Xms256m -Xmx512m -XX:+UseG1GC"
  JVM_ARGS: "-server -Djava.awt.headless=true"

resources:
  requests:
    memory: "512Mi"  # Should be larger than Xmx
  limits:
    memory: "768Mi"
```

### Node.js Applications

```yaml
env:
  NODE_OPTIONS: "--max-old-space-size=512 --gc-interval=100"
  UV_THREADPOOL_SIZE: "4"

resources:
  requests:
    memory: "256Mi"
  limits:
    memory: "512Mi"
```

## Load Testing

After deployment, test your API performance:

```bash
# Install k6 or similar load testing tool
# Example load test
k6 run --vus 50 --duration 60s - <<EOF
import http from 'k6/http';
import { check } from 'k6';

export default function() {
  let response = http.get('https://api.example.com/api/v1/health');
  check(response, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });
}
EOF
```

## Next Steps

- **Add circuit breakers**: Implement resilience patterns
- **Database migrations**: Add init containers for schema updates
- **API versioning**: Support multiple API versions
- **Caching**: Add Redis for response caching
- **Rate limiting**: Implement advanced rate limiting strategies

See related examples:
- [High Availability](./high-availability.yaml) - For production resilience
- [Azure Key Vault](./azure-key-vault.yaml) - For secret management
- [Monitoring Setup](./monitoring.yaml) - For comprehensive observability