openrouter_api 0.2.0

A Rust client library for the OpenRouter API
Documentation
# Contributing to OpenRouter API

Thank you for your interest in contributing to the OpenRouter API Rust client library! This document provides guidelines and instructions for contributing.

## Quick Start

1. **Fork and clone** the repository
2. **Install Rust** (latest stable version recommended)
3. **Run quality gates**: `./scripts/pre_quality.sh`
4. **Make your changes** following our guidelines
5. **Submit a pull request**

## Development Workflow

### Prerequisites

- Rust 1.70.0 or later
- `cargo` package manager
- Git

### Setting Up Development Environment

```bash
# Clone your fork
git clone https://github.com/YOUR_USERNAME/openrouter_api.git
cd openrouter_api

# Install dependencies and verify setup
cargo build
cargo test

# Run quality gates
./scripts/pre_quality.sh
```

### Quality Gates

**IMPORTANT**: All changes must pass our quality gates before submission:

```bash
# Run all quality checks
./scripts/pre_quality.sh

# Individual checks
cargo fmt              # Code formatting
cargo clippy           # Linting
cargo test             # Unit tests
cargo audit            # Security audit
cargo doc              # Documentation
```

### Code Standards

#### Code Style
- Follow standard Rust formatting (`cargo fmt`)
- Adhere to Clippy recommendations (`cargo clippy`)
- Write clear, self-documenting code
- Use meaningful variable and function names

#### Documentation
- Document all public APIs with rustdoc comments
- Include examples in documentation where helpful
- Update README.md for significant changes

#### Testing
- Write unit tests for all new functionality
- Maintain 100% test pass rate
- Add integration tests for complex features
- Test edge cases and error conditions

#### Security
- Never expose API keys or sensitive data in logs
- Use `SecureApiKey` for handling API credentials
- Sanitize error messages to prevent data leakage
- Follow secure coding practices

## Types of Contributions

### Bug Fixes
1. **Search existing issues** to avoid duplicates
2. **Create an issue** describing the bug if none exists
3. **Write a test** that reproduces the bug
4. **Fix the bug** and ensure the test passes
5. **Update documentation** if needed

### New Features
1. **Discuss the feature** in an issue first
2. **Design the API** following our patterns
3. **Implement with tests** and documentation
4. **Update examples** if applicable

### Documentation Improvements
- Fix typos, grammar, or unclear explanations
- Add missing documentation
- Improve code examples
- Update outdated information

## Code Architecture

### Key Patterns

#### Type-State Builder Pattern
The client uses compile-time state validation:
```rust
let client = OpenRouterClient::new()
    .with_base_url("https://openrouter.ai/api/v1/")?
    .with_api_key(api_key)?;  // Now in Ready state
```

#### Error Handling
Use the centralized `Error` enum and `Result<T>` type:
```rust
pub fn my_function() -> Result<MyType> {
    // ...
    Ok(result)
}
```

#### Security
Always use security utilities for sensitive data:
```rust
use crate::utils::security::create_safe_error_message;

// Good
let safe_msg = create_safe_error_message(&raw_error, "Context");

// Bad - never expose raw response bodies
return Err(Error::ApiError { message: raw_response, .. });
```

### Module Organization
- `client.rs`: Core client with type-state pattern
- `api/`: Endpoint-specific implementations
- `models/`: Domain models and data structures
- `types/`: Request/response type definitions
- `utils/`: Shared utilities (auth, validation, security)
- `error.rs`: Centralized error handling

## Testing Guidelines

### Writing Tests
```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_specific_behavior() {
        // Arrange
        let input = create_test_input();
        
        // Act
        let result = function_under_test(input);
        
        // Assert
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), expected_value);
    }
}
```

### Test Categories
- **Unit tests**: Test individual functions and methods
- **Integration tests**: Test complete workflows
- **Security tests**: Verify data protection and validation
- **Error tests**: Ensure proper error handling

## Submitting Changes

### Pull Request Process

1. **Create a feature branch** from `main`
   ```bash
   git checkout -b feature/your-feature-name
   ```

2. **Make your changes** following our guidelines

3. **Run quality gates** and ensure all tests pass
   ```bash
   ./scripts/pre_quality.sh
   ```

4. **Commit with clear messages**
   ```bash
   git commit -m "Add feature: clear description of what was added"
   ```

5. **Push and create PR**
   ```bash
   git push origin feature/your-feature-name
   ```

### Pull Request Requirements

✅ **Required for all PRs:**
- [ ] All quality gates pass (`./scripts/pre_quality.sh`)
- [ ] Tests written for new functionality
- [ ] Documentation updated for public API changes
- [ ] No breaking changes without discussion
- [ ] Clear, descriptive commit messages

✅ **PR Description should include:**
- What changes were made and why
- Any breaking changes
- Testing approach
- Documentation updates

### Review Process

1. **Automated checks** must pass (CI/CD)
2. **Code review** by maintainers
3. **Security review** for sensitive changes
4. **Documentation review** for public API changes

## Common Pitfalls

### Security Issues
❌ **Don't do this:**
```rust
// Exposing sensitive data
println!("Error: {}", response_body);
return Err(Error::ApiError { message: api_response, .. });
```

✅ **Do this instead:**
```rust
// Safe error handling
let safe_msg = create_safe_error_message(&response_body, "API call failed");
return Err(Error::ApiError { message: safe_msg, .. });
```

### Error Handling
❌ **Don't do this:**
```rust
// Swallowing errors
let result = risky_operation().unwrap_or_default();
```

✅ **Do this instead:**
```rust
// Proper error propagation
let result = risky_operation()
    .map_err(|e| Error::ConfigError(format!("Operation failed: {}", e)))?;
```

### Testing
❌ **Don't do this:**
```rust
// Brittle or incomplete tests
#[test]
fn test_something() {
    assert!(true); // Not testing anything useful
}
```

✅ **Do this instead:**
```rust
// Comprehensive, meaningful tests
#[test]
fn test_api_key_validation_rejects_short_keys() {
    let result = SecureApiKey::new("short");
    assert!(result.is_err());
    assert!(result.unwrap_err().to_string().contains("too short"));
}
```

## Getting Help

- **Documentation**: Check README.md and rustdoc comments
- **Issues**: Search existing issues or create a new one
- **Discussions**: Use GitHub Discussions for questions
- **Security**: Report security issues privately via email

## License

By contributing to this project, you agree that your contributions will be licensed under the same license as the project.