rust-conventions

star 17

Rust coding conventions and patterns for service development.

c9r-io By c9r-io schedule Updated 2/11/2026

name: rust-conventions description: Rust coding conventions and patterns for service development.

Rust Conventions

Tech Stack

These are recommended defaults; adjust to your stack.

Component Suggested Library
Web axum (+ tower middleware)
gRPC tonic
Database sqlx
Async tokio
Logging tracing
Testing mockall, wiremock

Code Organization

src/
├── domain/      # Pure models with validation
├── service/     # Business logic (depends on repo traits)
├── repository/  # Data access (mockable traits)
├── api/         # HTTP handlers (thin)
├── grpc/        # gRPC handlers (thin)
└── cache/       # Cache facade + NoOp cache for tests (optional)

Error Handling

// ❌ BAD
let result = db.query().await.ok();

// ✅ GOOD - use Result with context
let result = db.query()
    .await
    .context("Failed to query tenant")?;

// ✅ GOOD - custom error types
#[derive(thiserror::Error, Debug)]
pub enum ServiceError {
    #[error("Tenant not found: {0}")]
    TenantNotFound(Uuid),
    #[error("Database error: {0}")]
    Database(#[from] sqlx::Error),
}

Testing - NO EXTERNAL DEPENDENCIES

All tests run fast (~1-2s) with no Docker:

Component Approach
Repository Mock traits with mockall
Service Unit tests with mock repos
gRPC NoOpCacheManager + mocks
Keycloak wiremock HTTP mocking

Prohibited

  • No testcontainers
  • No real database connections
  • No real Redis connections
  • No faker library

Repository Mock Pattern

#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait TenantRepository: Send + Sync {
    async fn create(&self, input: &CreateTenantInput) -> Result<Tenant>;
    async fn find_by_id(&self, id: StringUuid) -> Result<Option<Tenant>>;
}

Service Layer Tests

#[cfg(test)]
mod tests {
    use super::*;
    use crate::repository::tenant::MockTenantRepository;

    #[tokio::test]
    async fn test_create_tenant() {
        let mut mock = MockTenantRepository::new();
        mock.expect_find_by_slug()
            .returning(|_| Ok(None));
        mock.expect_create()
            .returning(|input| Ok(Tenant { name: input.name.clone(), ..Default::default() }));

        let service = TenantService::new(Arc::new(mock), None);
        let result = service.create(input).await;
        assert!(result.is_ok());
    }
}

gRPC Tests

use crate::cache::NoOpCacheManager;

#[tokio::test]
async fn test_exchange_token() {
  let cache = NoOpCacheManager::new();  // No Redis
  let service = TokenExchangeService::new(jwt_manager, cache, repos...);
  // ...
}

Keycloak Tests

use wiremock::{Mock, ResponseTemplate, MockServer};

#[tokio::test]
async fn test_keycloak() {
    let mock_server = MockServer::start().await;
    Mock::given(method("POST"))
        .and(path("/realms/master/protocol/openid-connect/token"))
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
            "access_token": "mock-token"
        })))
        .mount(&mock_server).await;
    // Use mock_server.uri()
}

Commands

cargo test              # All tests (fast)
cargo llvm-cov --html   # Coverage report
cargo clippy            # Lint
cargo fmt               # Format
Install via CLI
npx skills add https://github.com/c9r-io/orchestrator --skill rust-conventions
Repository Details
star Stars 17
call_split Forks 2
navigation Branch main
article Path SKILL.md
More from Creator