Introduction
Welcome to Mycelium API Gateway, the ultimate solution for secure, flexible, and multi-tenant API management! Whether you’re building a robust platform or enhancing your downstream APIs, our gateway is designed to provide you with everything you need for seamless authentication, authorization, and security.
What is Mycelium?
Mycelium is an open and free API Gateway, designed to operate in modern, multi-tenant, and API-oriented environments. The project prioritizes architectural clarity, security, and extensibility, maintaining an explicit separation between technical concerns and organizational aspects of the project.
Mycelium acts as the entry layer for downstream services, being responsible for authentication, identity normalization, routing, and security policy enforcement. The gateway does not impose business logic, but provides authorization primitives that allow each service to evaluate permissions in an explicit, secure, and contextual manner.
Key Features
Authentication & Authorization
- OAuth2: Support for any OAuth2 identity provider with a few lines of configuration.
- Two-Factor Authentication (2FA): Built-in support for TOTP to ensure an extra layer of security when users opt to use the internal authentication system.
- Federated Identity Support: Integrate with external identity providers while maintaining full control over roles and permissions.
- Contextual Authorization (FBAC): Fine-grained, Feature-based Access Control with contextual evaluation at both gateway (RBAC for edge control) and downstream services (contextual FBAC for resource-level decisions).
Multi-Tenant Architecture
- Tenant Management: Create and manage tenants with subscription-based accounts.
- Role Assignment: Invite users to join tenants and assign them specific roles to streamline collaboration.
Secure Secrets Management
- Vault Integration: Leverage HashiCorp Vault for secure storage of secrets.
- Flexible Configurations: Use secrets stored in Vault, environment variables, or define them in YAML.
- Dynamic Secret Injection: Automate secure secret delivery to downstream APIs.
API Routing & Service Discovery
- Service Discovery: Discover downstream APIs and their capabilities, allowing dynamic integration and routing based on available services.
- Full Control of Downstream APIs: Downstream APIs can control whether their routes should be discovered or not, maintaining granular visibility control.
- Health Checks: Downstream APIs can define health checks to indicate when they are ready to receive requests. Health status is automatically updated based on the health checks and informed during discovery.
- Smart API Routing: Easily configure API routes with support for secure token-based authentication.
- Webhook Support: Define webhooks with secrets for secure callbacks and notifications.
TOML-Driven Configuration
- Simple and Intuitive: Manage all configurations (tenants, roles, permissions, routes, and security) with easy-to-read TOML files.
- Environment Flexibility: Combine TOML definitions with environment variables for maximum flexibility.
Security-First Design
- Layered Authorization: Gateway applies declarative controls (RBAC) while downstream services use contextual FBAC for fine-grained decisions.
- Profile Injection: Automatically inject identity context and capabilities to downstream APIs via Profile objects.
- Token Management: Store and securely pass tokens in request headers.
- Compliance Ready: Designed with modern security practices to meet enterprise compliance requirements.
Why Choose Mycelium API Gateway?
- Community-Driven and Open Source: Leverage a growing community while benefiting from an open-source model.
- Scalable and Modular: Designed to grow with your needs, from startups to enterprise-scale applications.
- Developer-Friendly: TOML-based configurations, secure secret management, and contextual authorization model make it easy to get started.
- Modern Authorization: Combines declarative RBAC at the gateway with fine-grained contextual FBAC in downstream services for maximum flexibility and security.
Conceptual Structure
Client
↓
API Gateway (auth, routing, edge RBAC)
↓
Downstream Services (contextual FBAC)
This separation ensures low coupling, high expressiveness, and security decisions close to the resource.
Next Steps
- Installation Guide - Learn how to install Mycelium
- Quick Start - Get up and running in minutes
- Configuration - Understand configuration options
- Authorization Model - Deep dive into the authorization system
License
Mycelium API Gateway is licensed under the Apache 2.0 License. Additional restrictions for commercial use apply under the Commons Clause. See the LICENSE file for details.
Installation Guide
This guide will walk you through the steps to install Mycelium API Gateway on your local machine. Mycelium API Gateway package includes twelve libs and services, available in Crates.io. It should be installed using the cargo package manager.
Prerequisites
Before you start, make sure you have the following installed on your machine:
Required
- Rust (version 1.70 or higher)
- Install via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- Install via rustup:
- Postgres (version 14 or higher)
- Database for tenant and user management
- Installation: PostgreSQL Downloads
- Redis (version 6 or higher)
- Caching for performance
- Installation: Redis Downloads
Optional but Recommended
- HashiCorp Vault
- Recommended for secret management in production environments
- Installation: Vault Installation
- Docker & Docker Compose
- Optional for quick deployment and development
- Installation: Docker Desktop
System Dependencies
Depending on your operating system, you may need additional system dependencies:
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libssl-dev postgresql-client
macOS:
brew install openssl pkg-config postgresql
Fedora/RHEL:
sudo dnf install -y gcc openssl-devel postgresql
Installation Methods
Method 1: Install using Cargo (Recommended for Production)
The simplest way to install Mycelium API Gateway is to use the cargo package manager:
cargo install mycelium-api
This will install the myc-api binary globally on your system.
Method 2: Build from Source
If you want to build from source or contribute to the project:
- Clone the repository:
git clone https://github.com/LepistaBioinformatics/mycelium.git
cd mycelium
- Build the project:
cargo build --release
- The binary will be available at
target/release/myc-api
Method 3: Using Docker
The easiest way to get started quickly is to use the Docker image:
docker pull sgelias/mycelium-api:latest
For development with docker-compose, see the Deploy Locally guide.
Database Setup
Mycelium API Gateway uses Postgres as the main datastore. Follow these steps to initialize the database:
Step 1: Ensure Postgres is Running
Verify that your Postgres instance is running:
psql --version
Step 2: Initialize the Database
Use the provided SQL script to initialize the database. The script creates the necessary database, user, and schema:
psql postgres://postgres:postgres@localhost:5432/postgres \
-f postgres/sql/up.sql \
-v db_password='REPLACE_ME'
Important Notes:
- Replace
postgres://postgres:postgres@localhost:5432/postgreswith your actual Postgres connection string - Replace
REPLACE_MEwith a strong password for the database user - The script creates a database named
mycelium-devby default
Step 3: Customize Database Name (Optional)
You can customize the database name using the db_name variable:
psql postgres://postgres:postgres@localhost:5432/postgres \
-f postgres/sql/up.sql \
-v db_name='my-mycelium-database' \
-v db_password='REPLACE_ME'
Additional customizations for db_user and db_role should be done in the up.sql script. Default values are:
- db_user:
mycelium-user - db_role:
service-role-mycelium
Vault Setup (Optional)
Vault is optional but highly recommended for secret management in production environments.
Step 1: Initialize Vault
Use the standard Vault CLI commands to initialize and unseal Vault:
vault operator init
You will receive output similar to:
Unseal Key 1: REPLACE_ME
Unseal Key 2: REPLACE_ME
Unseal Key 3: REPLACE_ME
Unseal Key 4: REPLACE_ME
Unseal Key 5: REPLACE_ME
Initial Root Token: REPLACE_ME
Important: Store these keys securely. You will need them to unseal Vault after each restart.
Step 2: Unseal Vault
Unseal Vault using at least 3 of the unseal keys:
vault operator unseal
# Enter unseal key 1
vault operator unseal
# Enter unseal key 2
vault operator unseal
# Enter unseal key 3
Step 3: Configure Vault for Mycelium
For detailed information on configuring Vault for use with Mycelium, refer to the Configuration Guide.
For more information on Vault, see the official Vault documentation.
Verify Installation
To verify that Mycelium is installed correctly:
If installed via Cargo:
myc-api --version
If built from source:
./target/release/myc-api --version
If using Docker:
docker run --rm sgelias/mycelium-api:latest --version
Next Steps
Now that you have Mycelium installed, proceed to:
- Quick Start Guide - Get your first instance running
- Configuration Guide - Learn about configuration options
- Deploy Locally - Set up a complete development environment
Troubleshooting
Common Issues
Issue: cargo install fails with SSL errors
- Solution: Ensure OpenSSL development libraries are installed
- Ubuntu/Debian:
sudo apt-get install libssl-dev - macOS:
brew install openssl
Issue: Database connection fails
- Solution: Verify Postgres is running and connection string is correct
- Check:
psql postgres://postgres:postgres@localhost:5432/postgres
Issue: Redis connection fails
- Solution: Verify Redis is running
- Check:
redis-cli ping(should returnPONG)
Issue: Permission denied when running up.sql
- Solution: Ensure you have superuser privileges or use a user with sufficient permissions
For more help, visit the GitHub Issues page.
Quick Start Guide
This guide will help you get Mycelium API Gateway up and running in minutes with a minimal configuration.
Prerequisites
Before starting, ensure you have completed the Installation Guide and have:
- Mycelium API Gateway installed
- Postgres database initialized
- Redis server running
Step 1: Prepare the Configuration File
Mycelium uses a TOML configuration file to define its settings. Create a minimal configuration file or use the example provided in the repository.
Using the Example Configuration
If you built from source, copy the example configuration:
cp settings/config.example.toml settings/config.toml
Minimal Configuration
Create a new file settings/config.toml with the following minimal content:
[core.accountLifeCycle]
domainName = "Mycelium Dev"
domainUrl = "http://localhost:8080"
tokenExpiration = 3600
noreplyName = "Mycelium No-Reply"
noreplyEmail = "noreply@example.com"
supportName = "Mycelium Support"
supportEmail = "support@example.com"
locale = "en-US"
tokenSecret = "your-secret-key-change-me-in-production"
[core.webhook]
acceptInvalidCertificates = true
consumeIntervalInSecs = 10
consumeBatchSize = 10
maxAttempts = 3
[diesel]
databaseUrl = "postgres://mycelium-user:YOUR_DB_PASSWORD@localhost:5432/mycelium-dev"
[smtp]
host = "smtp.example.com:587"
username = "user@example.com"
password = "your-smtp-password"
[queue]
emailQueueName = "email-queue"
consumeIntervalInSecs = 5
[redis]
protocol = "redis"
hostname = "localhost:6379"
password = ""
[auth]
internal = "enabled"
jwtSecret = "your-jwt-secret-change-me-in-production"
jwtExpiresIn = 86400
tmpExpiresIn = 3600
[api]
serviceIp = "0.0.0.0"
servicePort = 8080
serviceWorkers = 4
gatewayTimeout = 30
healthCheckInterval = 120
maxRetryCount = 3
allowedOrigins = ["*"]
[api.cache]
jwksTtl = 3600
emailTtl = 120
profileTtl = 120
[api.logging]
level = "info"
format = "ansi"
target = "stdout"
Important: Replace the following placeholders:
YOUR_DB_PASSWORD- The password you set during database initializationyour-secret-key-change-me-in-production- A strong secret for token encryptionyour-jwt-secret-change-me-in-production- A strong secret for JWT signing
Step 2: Define Routes in Configuration
Routes are now defined directly in the main configuration file using TOML’s array of tables syntax. Add the following to your config.toml:
# ------------------------------------------------------------------------------
# SERVICE CONFIGURATIONS
# ------------------------------------------------------------------------------
[api.services]
# Example downstream service (optional)
[[my-service]]
host = "localhost:3000"
protocol = "http"
[[my-service.path]]
group = "public"
path = "/api/*"
methods = ["GET", "POST", "PUT", "DELETE"]
Step 3: Start Mycelium
Now you can start the Mycelium API Gateway:
If installed via Cargo:
SETTINGS_PATH=settings/config.toml myc-api
If built from source:
SETTINGS_PATH=settings/config.toml ./target/release/myc-api
If using Docker:
docker run -d \
--name mycelium-api \
-p 8080:8080 \
-v $(pwd)/settings:/app/settings \
-e SETTINGS_PATH=settings/config.toml \
sgelias/mycelium-api:latest
Step 4: Verify the Gateway is Running
Test the health check endpoint:
curl http://localhost:8080/health
You should receive a response indicating the gateway is healthy.
Step 5: Test Authentication (Optional)
To test the internal authentication system, you’ll need to:
- Create a user account
- Verify the email (or skip verification in development)
- Login to receive a JWT token
For detailed authentication workflows, see the Authorization Guide.
Common Quick Start Commands
Check Logs
If you’re running in the foreground, logs will appear in the terminal. For Docker:
docker logs -f mycelium-api
Stop the Gateway
Press Ctrl+C if running in the foreground, or for Docker:
docker stop mycelium-api
Restart with Configuration Changes
After modifying the configuration file, restart the gateway:
# Kill the current process and restart
SETTINGS_PATH=settings/config.toml myc-api
Environment Variables
Mycelium supports configuration through environment variables. You can override any TOML setting:
# Set database URL via environment variable
export DATABASE_URL="postgres://user:pass@localhost:5432/mycelium"
SETTINGS_PATH=settings/config.toml myc-api
For more details on environment variable configuration, see the Configuration Guide.
Next Steps
Now that you have Mycelium running, you can:
- Configure Downstream Services: Learn how to configure routes to proxy to your backend services
- Set Up Authentication: Configure OAuth2 providers or use internal authentication
- Enable Vault: Secure your secrets with HashiCorp Vault
- Deploy to Production: See the deployment guides for production-ready setups
- Run Tests: Learn how to run the test suite
Troubleshooting
Gateway won’t start
Check the configuration file syntax:
# Validate TOML syntax
cat settings/config.toml | grep -v "^#" | grep -v "^$"
Check database connectivity:
psql postgres://mycelium-user:YOUR_PASSWORD@localhost:5432/mycelium-dev -c "SELECT 1"
Check Redis connectivity:
redis-cli ping
Port already in use
If port 8080 is already in use, change the servicePort in config.toml:
[api]
servicePort = 8081 # Use a different port
Cannot connect to downstream services
Ensure:
- The downstream service is running
- The host and port in
config.tomlare correct - The protocol (http/https) matches the downstream service
For more help, visit the GitHub Issues page.
Configuration Guide
This document describes the configurations of the TOML file used to set up the Mycelium API Gateway. An example configuration file can be found at settings/config.example.toml in the repository.
Configuration File Location
Mycelium reads its configuration from a TOML file specified via the SETTINGS_PATH environment variable:
SETTINGS_PATH=settings/config.toml myc-api
Configuration Methods
Mycelium provides three different ways to configure settings:
- Directly in the TOML file (for development purposes)
- Environment variables (for production purposes)
- Externally in a Vault server (for production, highly recommended)
All three options are valid for any configuration, but we recommend using Vault for storing secrets in production environments.
Example: Three Ways to Configure
Using directly in the TOML file:
[core.accountLifeCycle]
tokenSecret = "my-secret"
Using environment variables:
[core.accountLifeCycle]
tokenSecret = { env = "MYC_TOKEN_SECRET" }
Then set the environment variable:
export MYC_TOKEN_SECRET="my-secret"
Using Vault:
[core.accountLifeCycle]
tokenSecret = { vault = { path = "myc/core/accountLifeCycle", key = "tokenSecret" } }
Security Best Practice: Mycelium will try to resolve the variables at runtime, so it is not necessary to restart the API Gateway after changing the configuration in Vault.
1. Vault Configurations (vault)
Highly recommended for production environments.
If you opt to use the Vault server to store secrets, configure the following options:
[vault.define]
url = "http://localhost:8200"
versionWithNamespace = "v1/kv"
token = "your-vault-token"
Configuration Options:
url: The URL of the Vault server. Should include the protocol, hostname, and port number if necessary.versionWithNamespace: The API version used to interact with the Vault server. Example:v1/kv.token: The token used to authenticate with the Vault server. For obvious reasons, this should be configured using environment variables in production.
Example with environment variable:
[vault.define]
url = "http://localhost:8200"
versionWithNamespace = "v1/kv"
token = { env = "VAULT_TOKEN" }
2. Core Configurations (core)
Here resides the core configurations of the API Gateway. Configs defined here should be used to configure the basic application lifecycle and webhooks.
2.1 Account Lifecycle (accountLifeCycle)
[core.accountLifeCycle]
domainName = "Mycelium"
domainUrl = "https://mycelium.com"
tokenExpiration = 3600
noreplyName = "Mycelium No-Reply"
noreplyEmail = "noreply@mycelium.com"
supportName = "Mycelium Support"
supportEmail = "support@mycelium.com"
locale = "en-US"
tokenSecret = "your-secret-key"
Configuration Options:
domainName: The human-friendly name of the domain. Usually this is the frontend domain name. Example:Mycelium.domainUrl: The URL of the domain. Example:https://mycelium.com.tokenExpiration: Token expiration time in seconds.noreplyName/noreplyEmail: Name and email for automatic messages.supportName/supportEmail: Name and email for support.locale: Default locale. Emails will be sent in this locale.tokenSecret: A unique secret used to encrypt JWT tokens.
2.2 Webhook (webhook)
[core.webhook]
acceptInvalidCertificates = true
consumeIntervalInSecs = 10
consumeBatchSize = 10
maxAttempts = 3
Configuration Options:
acceptInvalidCertificates: Allows self-signed certificates (useful for development).consumeIntervalInSecs: The interval in seconds between each batch of webhook dispatch events.consumeBatchSize: The number of events processed per batch.maxAttempts: The maximum number of attempts to process an event.
3. SQL Database Adapter Settings (diesel)
[diesel]
databaseUrl = "postgres://mycelium-user:password@localhost:5432/mycelium-dev"
Configuration Options:
databaseUrl: The database URL. This is highly recommended to be stored in Vault or as an environment variable.
Example with Vault:
[diesel]
databaseUrl = { vault = { path = "myc/database", key = "url" } }
4. Notifier Adapter Settings (smtp and queue)
4.1 SMTP (smtp)
[smtp]
host = "smtp.gmail.com:587"
username = "user@gmail.com"
password = "your-password"
Configuration Options:
host: The SMTP server address including port.username/password: SMTP credentials.
4.2 Email Queue (queue)
[queue]
emailQueueName = "email-queue"
consumeIntervalInSecs = 5
Configuration Options:
emailQueueName: The name of the email queue.consumeIntervalInSecs: The interval in seconds between each batch of email dispatch events.
5. Redis Settings (redis)
Redis is used to store cache and session data.
[redis]
protocol = "redis"
hostname = "localhost:6379"
password = ""
Configuration Options:
protocol: The protocol used to connect to the Redis server (usuallyredisorredissfor secure connection).hostname: The address of the Redis server including port.password: The password used to connect to the Redis server (leave empty if no password).
6. Authentication Settings (auth)
Mycelium provides a flexible authentication system that allows you to configure internal and external authentication providers.
6.1 Internal Authentication (internal)
Internal authentication is the default authentication provider and is used to authenticate users against the Mycelium database.
[auth]
internal = "enabled"
jwtSecret = "your-jwt-secret"
jwtExpiresIn = 86400
tmpExpiresIn = 3600
Configuration Options:
internal: Set to"enabled"to enable internal authentication.jwtSecret: A unique secret used to encrypt JWT tokens.jwtExpiresIn: JWT expiration time in seconds (default: 86400 = 24 hours).tmpExpiresIn: Temporary token expiration time in seconds. This is used to generate temporary tokens during password reset and account creation processes.
6.2 External Authentication (external)
External authentication is used to authenticate users against any external provider that supports OAuth 2.0.
[[auth.external.define]]
issuer = "https://accounts.google.com"
jwksUri = "https://www.googleapis.com/oauth2/v3/certs"
userInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo"
audience = "your-google-client-id"
Configuration Options:
issuer: The issuer of the OAuth 2.0 provider. This is a URL that identifies the provider.jwksUri: The URI of the JWKS endpoint. This is a URL that points to the JWKS (JSON Web Key Set) endpoint of the provider.userInfoUrl: The URI of the user info endpoint. This is a URL that points to the user info endpoint of the provider.audience: The audience of the OAuth 2.0 provider. This is a string that identifies the API that the provider is used for.
Example with Multiple Providers:
# Google OAuth2
[[auth.external.define]]
issuer = "https://accounts.google.com"
jwksUri = "https://www.googleapis.com/oauth2/v3/certs"
userInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo"
audience = "your-google-client-id"
# Microsoft
[[auth.external.define]]
issuer = "https://sts.windows.net/{tenantId}/"
jwksUri = "https://login.microsoftonline.com/{tenantId}/discovery/keys"
userInfoUrl = "https://graph.microsoft.com/oidc/userinfo"
audience = "00000003-0000-0000-c000-000000000000"
# Auth0
[[auth.external.define]]
issuer = "https://{app-name}.auth0.com/"
jwksUri = "https://{app-name}.auth0.com/.well-known/jwks.json"
userInfoUrl = "https://{app-name}.auth0.com/userinfo"
audience = "https://{app-name}.auth0.com/api/v2/"
7. API Settings (api)
7.1 Service Settings
[api]
serviceIp = "0.0.0.0"
servicePort = 8080
serviceWorkers = 4
gatewayTimeout = 30
healthCheckInterval = 120
maxRetryCount = 3
allowedOrigins = [
"http://localhost:8080",
"https://localhost:8080",
"http://localhost:3000"
]
[api.cache]
jwksTtl = 3600
emailTtl = 120
profileTtl = 120
Configuration Options:
serviceIp: Service IP address. Usually0.0.0.0to listen on all interfaces.servicePort: Service port. Usually8080.serviceWorkers: Number of worker threads. Usually4or number of CPU cores.gatewayTimeout: Gateway timeout in seconds. Usually30.allowedOrigins: Array of allowed CORS origins. Use["*"]for development, specify exact origins for production.healthCheckInterval: Health check interval in seconds. Usually120.maxRetryCount: Maximum retry count for failed requests. Usually3.cache.jwksTtl: JWKS cache TTL in seconds. Usually3600(1 hour).cache.emailTtl: Email cache TTL in seconds. Usually120.cache.profileTtl: Profile cache TTL in seconds. Usually120.
7.2 Logging Settings (logging)
[api.logging]
level = "info"
format = "ansi"
target = "stdout"
Configuration Options:
level: Log level. Options:trace,debug,info,warn,error. Can be set globally or per module.format: Log format. Options:jsonl(JSON Lines),ansi(colored terminal output).target: Log destination. Options:stdout,file, orcollector(for Jaeger).
Example with Per-Module Log Levels:
[api.logging]
level = "mycelium_base=trace,myc_api=debug,actix_web=warn"
format = "jsonl"
target = "stdout"
Example with File Target:
[api.logging]
level = "info"
format = "jsonl"
target = { file = { path = "logs/api.log" } }
Example with Jaeger/OpenTelemetry Collector:
[api.logging]
level = "info"
format = "jsonl"
target = { collector = { name = "mycelium-api", host = "otel-collector", protocol = "grpc", port = 4317 } }
7.3 TLS Settings (tls)
[api.tls.define]
tlsCert = '''
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
'''
tlsKey = '''
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
'''
Configuration Options:
tlsCert/tlsKey: TLS certificates. Use triple quotes (''') for multi-line strings.
Example with Vault:
[api.tls.define]
tlsCert = { vault = { path = "myc/api/tls", key = "tlsCert" } }
tlsKey = { vault = { path = "myc/api/tls", key = "tlsKey" } }
To disable TLS:
tls = "disabled"
7.4 Service Configurations
Services and routes are now configured directly in the main TOML file. See the Downstream APIs Configuration for detailed examples.
Complete Configuration Example
For a complete example with all options, see settings/config.example.toml in the repository:
cat settings/config.example.toml
Environment Variables Reference
You can override any configuration using environment variables. The environment variable name should match the TOML path using underscores and uppercase letters:
# Override service port
export API_SERVICE_PORT=8081
# Override database URL
export DIESEL_DATABASE_URL="postgres://user:pass@localhost/db"
# Override JWT secret
export AUTH_JWT_SECRET="my-secret"
Validation
Mycelium validates the configuration at startup. If there are errors, they will be displayed in the logs with suggestions for fixing them.
To validate your configuration without starting the server:
# This will validate and exit
SETTINGS_PATH=settings/config.toml myc-api --validate
Next Steps
- Downstream APIs Configuration - Learn how to configure routes and downstream services
- Deploy Locally - Set up a complete development environment
- Quick Start - Get started with a minimal configuration
Troubleshooting
Issue: Configuration file not found
- Solution: Ensure
SETTINGS_PATHpoints to the correct file path
Issue: TOML parsing errors
- Solution: Validate TOML syntax using an online validator or
tomlfmt
Issue: Vault connection fails
- Solution: Ensure Vault is running and unsealed, and the token is valid
For more help, visit the GitHub Issues page.
Deploy Locally with Docker Compose
This guide explains how to deploy Mycelium API Gateway locally using Docker Compose. This is the recommended approach for development and testing, as it provides a complete environment with all dependencies.
Prerequisites
Before starting, ensure you have:
- Docker (version 20.10 or higher)
- Docker Compose (version 2.0 or higher)
Install Docker Desktop for your platform:
Quick Start with Docker Compose
Step 1: Clone the Repository
git clone https://github.com/LepistaBioinformatics/mycelium.git
cd mycelium
Step 2: Review and Customize Configuration
The repository includes example configuration files. Copy and customize them:
# Copy example configuration
cp settings/config.example.toml settings/config.toml
# Review and update the configuration
nano settings/config.toml
Important settings to review:
- Database credentials
- Redis configuration
- SMTP settings (if using email notifications)
- Vault configuration (if using Vault)
Step 3: Start the Services
Start all services using Docker Compose:
docker-compose up -d
This will start:
- Postgres - Database for tenant and user management
- Redis - Caching layer
- Vault - Secret management (optional)
- Mycelium API Gateway - The main gateway service
Step 4: Initialize the Database
Wait for Postgres to be ready, then initialize the database:
# Wait for Postgres to be ready
docker-compose exec postgres pg_isready
# Initialize the database
docker-compose exec postgres psql -U postgres -f /docker-entrypoint-initdb.d/up.sql \
-v db_password='mycelium-password'
Alternatively, if the SQL script is mounted:
docker-compose exec -T postgres psql -U postgres < postgres/sql/up.sql
Step 5: Verify Services
Check that all services are running:
docker-compose ps
You should see all services in the “Up” state.
Test the API Gateway health endpoint:
curl http://localhost:8080/health
Docker Compose Configuration
Understanding the docker-compose.yaml
The docker-compose.yaml file (docker-compose files use YAML format, but Mycelium configuration uses TOML) defines the services required for Mycelium:
version: '3.8'
services:
postgres:
image: postgres:14
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
- ./postgres/sql:/docker-entrypoint-initdb.d
redis:
image: redis:7
ports:
- "6379:6379"
volumes:
- redis-data:/data
vault:
image: vault:1.13
ports:
- "8200:8200"
environment:
VAULT_DEV_ROOT_TOKEN_ID: mycelium-dev-token
VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
cap_add:
- IPC_LOCK
mycelium-api:
image: sgelias/mycelium-api:latest
ports:
- "8080:8080"
environment:
SETTINGS_PATH: /app/settings/config.toml
volumes:
- ./settings:/app/settings
depends_on:
- postgres
- redis
volumes:
postgres-data:
redis-data:
Customizing Services
You can customize service configurations by modifying docker-compose.yaml or creating a docker-compose.override.yaml file:
# docker-compose.override.yaml
version: '3.8'
services:
mycelium-api:
environment:
LOG_LEVEL: debug
ports:
- "8081:8080" # Change external port
Development Workflow
Building from Source
If you want to build Mycelium from source instead of using the pre-built image:
- Update
docker-compose.yaml:
services:
mycelium-api:
build:
context: .
dockerfile: Dockerfile
# Remove the 'image' line
- Build and start:
docker-compose up -d --build
Hot Reload for Development
For development with hot reload, you can mount your source code:
services:
mycelium-api:
volumes:
- ./settings:/app/settings
- ./src:/app/src # Mount source code
- ./Cargo.toml:/app/Cargo.toml
command: cargo watch -x run
Then rebuild:
docker-compose up -d --build
Viewing Logs
View logs for all services:
docker-compose logs -f
View logs for a specific service:
docker-compose logs -f mycelium-api
docker-compose logs -f postgres
docker-compose logs -f redis
Stopping Services
Stop all services:
docker-compose down
Stop and remove volumes (WARNING: This deletes all data):
docker-compose down -v
Working with Vault
If using Vault for secret management, initialize it after starting:
Step 1: Initialize Vault
docker-compose exec vault vault operator init
Save the unseal keys and root token securely.
Step 2: Unseal Vault
# Unseal with 3 keys
docker-compose exec vault vault operator unseal <KEY1>
docker-compose exec vault vault operator unseal <KEY2>
docker-compose exec vault vault operator unseal <KEY3>
Step 3: Store Secrets
# Login with root token
docker-compose exec vault vault login <ROOT_TOKEN>
# Store a secret
docker-compose exec vault vault kv put secret/mycelium/database url="postgres://user:pass@postgres:5432/mycelium"
Step 4: Update Configuration
Update settings/config.toml to use Vault:
[vault.define]
url = "http://vault:8200"
versionWithNamespace = "v1/secret"
token = { env = "VAULT_TOKEN" }
[diesel]
databaseUrl = { vault = { path = "mycelium/database", key = "url" } }
Database Management
Accessing the Database
Connect to the Postgres database:
docker-compose exec postgres psql -U mycelium-user -d mycelium-dev
Running Migrations
If you have database migrations:
docker-compose exec mycelium-api diesel migration run
Backing Up the Database
Create a database backup:
docker-compose exec -T postgres pg_dump -U mycelium-user mycelium-dev > backup.sql
Restore from backup:
docker-compose exec -T postgres psql -U mycelium-user mycelium-dev < backup.sql
Environment-Specific Configurations
Development Environment
Create docker-compose.dev.yaml (note: docker-compose files remain in YAML format):
version: '3.8'
services:
mycelium-api:
environment:
RUST_LOG: debug
RUST_BACKTRACE: 1
volumes:
- ./settings:/app/settings
Use it with:
docker-compose -f docker-compose.yaml -f docker-compose.dev.yaml up -d
Production Environment
For production, use separate configuration:
docker-compose -f docker-compose.yaml -f docker-compose.prod.yaml up -d
Troubleshooting
Service won’t start
Check the logs:
docker-compose logs mycelium-api
Database connection issues
Ensure Postgres is ready:
docker-compose exec postgres pg_isready
Check database exists:
docker-compose exec postgres psql -U postgres -l
Port conflicts
If ports are already in use, modify docker-compose.yaml:
services:
mycelium-api:
ports:
- "8081:8080" # Use different external port
Reset Everything
To completely reset your environment:
docker-compose down -v
docker-compose up -d
# Re-initialize database
Next Steps
- Configuration Guide - Detailed configuration options
- Downstream APIs - Configure routing to backend services
- Running Tests - Run the test suite
Additional Resources
Mycelium Authorization Model
This document describes the Mycelium authorization model, its principles, formal classification, and architectural decisions. It is strictly technical and does not address aspects of project governance or maintenance.
Overview
Mycelium adopts a contextual authorization model, designed for multi-tenant and API-oriented environments. Unlike approaches based exclusively on roles (RBAC), Mycelium evaluates identity attributes, resource scope, and request context at execution time.
Formally, the model fits as FBAC (Fine-grained / Feature-based Access Control), using RBAC only as a complementary primitive.
Design Principles
- Clear separation between authentication, identity enrichment, and authorization
- Explicit access decision close to the resource
- Progressive reduction of capabilities
- Composable and deterministic primitives
- Avoid rigid global policies
Layered Authorization
Gateway (Coarse-grained)
At the gateway, Mycelium applies declarative controls per route, such as:
- Public or protected group
- Minimum required roles
- Permissions associated with roles
These checks determine whether the request can or cannot be routed to the downstream service.
Downstream (Fine-grained)
In downstream services, authorization is done in a contextual and explicit manner, using the Profile injected by the gateway.
Conceptual example:
profile
.on_tenant(tenant_id)
.on_account(account_id)
.with_write_access()
.with_roles(vec![SystemActor::AccountManager])
.get_related_account_or_error()?;
Each call reduces the set of available capabilities, never expands it.
The Profile
The Profile represents the complete identity context at the time of the request and acts as an active authorization object.
It can contain:
- Identity
- Related tenants and accounts
- Roles
- Scopes and access levels
The Profile exposes primitives such as on_tenant, on_account, and with_roles, which enable deterministic and auditable decisions.
Formal Classification
- RBAC: used partially and declaratively at the gateway
- ABAC: present in explicit use of attributes
- FBAC: dominant model, contextual and resource-oriented
Auditing and Observability
Each authorization decision can be treated as a logical event containing:
- Resource
- Action
- Applied context
- Decision result
This model is compatible with distributed observability and deterministic auditing.
Model Evolution
The current model allows incremental evolution to:
- Declarative policy DSL
- Decision caching
- Integration with external engines (optional)
Conclusion
Mycelium implements a modern authorization model, combining declarative controls at the gateway with contextual decisions close to the resource. This design favors clarity, security, and scalability without introducing unnecessary dependencies.
Downstream APIs Configuration
Downstream services are configured directly in the main TOML configuration file. This guide explains how to configure routes, security groups, and authentication for your backend services.
Configuration Location
All service and route configurations are defined in your main config.toml file under the [api.services] section:
SETTINGS_PATH=settings/config.toml myc-api
Service Configuration
Services are defined using TOML’s array of tables syntax ([[service-name]]). Each service includes configuration options and associated routes.
Required Fields
Service Name: The table name (e.g., [[my-service]])
- Used to identify the service in the gateway URL path
- Should use kebab-case (e.g.,
my-service)
host: The service host
- Should include the port number
- Do not include the protocol
- Example:
"localhost:3000"or"api.example.com:443"
protocol: The connection protocol
- Options:
"http"or"https"
Routes ([[service-name.path]]): Array of route definitions
- Each route is defined as
[[service-name.path]] - See the Routes Section for details
Optional Fields
discoverable: Enable AI-aware service discovery
- Set to
trueto make the service discoverable by LLM agents - Default:
false
id: Unique identifier (UUID v4 recommended)
description: Human-readable service description
openapiPath: Path to OpenAPI specification
healthCheckPath: Health check endpoint path
capabilities: Array of capability strings
serviceType: Type of service (e.g., "rest-api")
isContextApi: Whether this is a context API
proxyAddress: Proxy server address (if using a proxy)
Basic Service Example
[api.services]
[[my-service]]
host = "localhost:3000"
protocol = "http"
[[my-service.path]]
group = "public"
path = "/api/users/*"
methods = ["GET", "POST", "PUT", "DELETE"]
Service with Multiple Hosts (Load Balancing)
[[api-service]]
hosts = ["api-01.example.com:8080", "api-02.example.com:8080", "api-03.example.com:8080"]
protocol = "https"
[[api-service.path]]
group = "authenticated"
path = "/api/*"
methods = ["ALL"]
Secrets Configuration
Secrets are used to authenticate Mycelium with downstream services.
Query Parameter Secret
[[legacy-api]]
host = "legacy.example.com:8080"
protocol = "https"
[[legacy-api.secret]]
name = "legacy-token"
queryParameter = { name = "token", token = "my-secret-token" }
[[legacy-api.path]]
group = "public"
path = "/legacy/*"
methods = ["GET"]
secretName = "legacy-token"
Authorization Header Secret
[[protected-api]]
host = "api.example.com:443"
protocol = "https"
[[protected-api.secret]]
name = "auth-header"
authorizationHeader = { name = "Authorization", prefix = "Bearer ", token = "my-bearer-token" }
[[protected-api.path]]
group = "public"
path = "/protected/*"
methods = ["ALL"]
secretName = "auth-header"
Secrets from Environment Variables
# Set environment variable with inline TOML format
export MY_SECRET='{ queryParameter = { name = "token", token = "my-secret-01" } }'
[[my-service]]
host = "localhost:3000"
protocol = "http"
[[my-service.secret]]
name = "secret-query-token"
env = "MY_SECRET"
Secrets from Vault
[[my-service]]
host = "localhost:3000"
protocol = "http"
[[my-service.secret]]
name = "secret-auth-header"
vault = { path = "myc/services/my-service", key = "authHeader" }
AI-Aware Service Discovery
When discoverable = true, additional configuration options enhance AI discoverability:
[[auth-service]]
id = "550e8400-e29b-41d4-a716-446655440000"
host = "auth.example.com:443"
protocol = "https"
discoverable = true
description = "Authentication and authorization service"
openapiPath = "/api/openapi.json"
healthCheckPath = "/health"
capabilities = ["authenticate", "OAuth2", "2FA", "JWT"]
serviceType = "rest-api"
isContextApi = true
[[auth-service.path]]
group = "public"
path = "/auth/*"
methods = ["POST"]
Routes
Routes define how requests are matched and secured. Each route is defined as [[service-name.path]].
Required Fields
group: Security group for the route
- Determines authentication and authorization requirements
- See Security Groups for options
path: URL path pattern
- Supports wildcards:
/users/* - Exact matches:
/users/profile
methods: Array of HTTP methods
- Standard:
["GET"],["POST", "PUT"], etc. - Special:
["ALL"]matches all methods
Optional Fields
secretName: Reference to a secret defined at service level
acceptInsecureRouting: Allow self-signed certificates (default: false)
Security Groups
Mycelium supports seven security groups for route protection:
1. Public Routes
No authentication required.
[[health-service]]
host = "localhost:8080"
protocol = "http"
[[health-service.path]]
group = "public"
path = "/health"
methods = ["GET"]
2. Authenticated Routes
Requires valid JWT token. User email injected in x-mycelium-email header.
[[user-service]]
host = "users.example.com:443"
protocol = "https"
[[user-service.path]]
group = "authenticated"
path = "/user/profile"
methods = ["GET", "PUT"]
3. Protected Routes
Requires authentication and valid profile. Full profile injected in x-mycelium-profile header.
[[dashboard-service]]
host = "dashboard.example.com:443"
protocol = "https"
[[dashboard-service.path]]
group = "protected"
path = "/dashboard/*"
methods = ["GET"]
4. Protected by Roles
Requires authentication and specific role(s).
[[admin-service]]
host = "admin.example.com:443"
protocol = "https"
[[admin-service.path]]
group = { protectedByRoles = [{ slug = "admin" }, { slug = "super-admin" }] }
path = "/admin/*"
methods = ["ALL"]
5. Protected by Roles with Permissions
Requires authentication and specific role-permission combinations.
[[content-service]]
host = "content.example.com:443"
protocol = "https"
[[content-service.path]]
group = { protectedByRoles = [{ slug = "editor", permission = "write" }, { slug = "admin", permission = "write" }] }
path = "/content/edit/*"
methods = ["POST", "PUT", "DELETE"]
[[content-service.path]]
group = { protectedByRoles = [{ slug = "viewer", permission = "read" }, { slug = "editor", permission = "read" }] }
path = "/content/view/*"
methods = ["GET"]
6. Protected by Service Token with Role
Requires valid service token with specific role(s).
[[service-api]]
host = "service.internal:8080"
protocol = "http"
[[service-api.path]]
group = { protectedByServiceTokenWithRole = { roles = ["service-admin"] } }
path = "/service-api/*"
methods = ["ALL"]
Service token format:
tid=c8282c6d-ce0b-4fed-a4e8-8e8a70f5b789;rid=8d7b119b-a12b-4ff1-9db0-5b6d05794282;r=newbie;edt=2025-01-11T21:51:01-03:00;sig=asd132f141e1...
7. Protected by Service Token with Permissioned Roles
Requires valid service token with specific role-permission combinations.
[[service-data]]
host = "data.internal:8080"
protocol = "http"
[[service-data.path]]
group = { protectedByServiceTokenWithPermissionedRoles = { permissionedRoles = [["admin", "write"], ["viewer", "read"]] } }
path = "/service-data/*"
methods = ["GET", "POST"]
Complete Example
Here’s a complete configuration with multiple services:
[api.services]
# Health check endpoint
[[health-check]]
host = "localhost:8080"
protocol = "http"
[[health-check.path]]
group = "public"
path = "/health"
methods = ["GET"]
# User service with authentication
[[user-service]]
host = "users.example.com:443"
protocol = "https"
[[user-service.path]]
group = "authenticated"
path = "/users/me"
methods = ["GET", "PUT"]
[[user-service.path]]
group = "protected"
path = "/users/preferences"
methods = ["GET", "POST"]
# Admin service with role-based access
[[admin-service]]
host = "admin.example.com:443"
protocol = "https"
[[admin-service.path]]
group = { protectedByRoles = [{ slug = "admin" }, { slug = "super-admin" }] }
path = "/admin/*"
methods = ["ALL"]
# Content service with permissioned roles
[[content-service]]
host = "content.example.com:443"
protocol = "https"
discoverable = true
description = "Content management service"
healthCheckPath = "/health"
capabilities = ["content-management", "versioning"]
[[content-service.path]]
group = { protectedByRoles = [{ slug = "editor", permission = "write" }] }
path = "/content/edit/*"
methods = ["POST", "PUT", "DELETE"]
[[content-service.path]]
group = { protectedByRoles = [{ slug = "viewer", permission = "read" }] }
path = "/content/view/*"
methods = ["GET"]
# Legacy API with authentication secret
[[legacy-api]]
host = "legacy.internal:8080"
protocol = "http"
[[legacy-api.secret]]
name = "legacy-token"
queryParameter = { name = "api_key", token = { env = "LEGACY_API_KEY" } }
[[legacy-api.path]]
group = "public"
path = "/legacy/*"
methods = ["GET"]
secretName = "legacy-token"
acceptInsecureRouting = true
Header Injection
Mycelium automatically injects headers to downstream services based on the security group:
| Security Group | Injected Headers |
|---|---|
authenticated | x-mycelium-email |
protected | x-mycelium-profile |
protectedByRoles | x-mycelium-profile |
The x-mycelium-profile header contains a JSON object with user information, roles, and permissions.
Testing Routes
Test your route configuration using curl:
# Test public route
curl http://localhost:8080/health
# Test authenticated route (requires JWT)
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
http://localhost:8080/users/me
# Test with service token
curl -H "Authorization: ServiceToken tid=...;rid=...;r=admin;edt=...;sig=..." \
http://localhost:8080/service-api/data
Troubleshooting
Route not matching:
- Verify path pattern includes wildcards if needed (
/*) - Check method is in the
methodsarray - Ensure service name is correct in URL path
Authentication failing:
- Verify JWT token is valid and not expired
- Check security group matches authentication method
- Ensure roles/permissions are correctly assigned
Downstream service not reachable:
- Verify host and port are correct
- Check protocol (http vs https) matches
- Test direct connection to downstream service
- Review
acceptInsecureRoutingfor self-signed certs
Configuration syntax errors:
- Validate TOML syntax using an online validator
- Check array of tables syntax:
[[service-name]] - Ensure inline tables use correct syntax:
{ key = "value" }
Next Steps
- Authorization Model - Understanding security in depth
- Configuration Guide - Main configuration options
- Running Tests - Test your setup
For more help, visit the GitHub Issues page.
Running Tests
This guide explains how to run the test suite for Mycelium API Gateway. Mycelium includes comprehensive unit tests, integration tests, and end-to-end tests to ensure code quality and reliability.
Prerequisites
Before running tests, ensure you have:
- Rust toolchain (version 1.70 or higher)
- Development dependencies installed
- Test environment configured (Postgres, Redis running)
Quick Start
Run all tests with a single command:
cargo test
This will compile and run all unit tests, integration tests, and documentation tests in the project.
Test Categories
Mycelium’s test suite is organized into several categories:
Unit Tests
Unit tests verify individual functions and modules in isolation.
Run all unit tests:
cargo test --lib
Run tests for a specific module:
cargo test --lib users
cargo test --lib auth
cargo test --lib routing
Run a specific test:
cargo test --lib test_user_creation
Integration Tests
Integration tests verify interactions between multiple components.
Run all integration tests:
cargo test --test '*'
Run a specific integration test:
cargo test --test api_integration
Documentation Tests
Documentation tests ensure code examples in documentation are correct.
Run documentation tests:
cargo test --doc
Test Environment Setup
Some tests require external services (Postgres, Redis). You can set these up in multiple ways:
Option 1: Using Docker Compose (Recommended)
Start test dependencies using Docker Compose:
# Start test services
docker-compose -f docker-compose.test.yaml up -d
# Run tests
cargo test
# Stop test services
docker-compose -f docker-compose.test.yaml down
Option 2: Local Services
If you have Postgres and Redis running locally:
# Set test database URL
export TEST_DATABASE_URL="postgres://postgres:postgres@localhost:5432/mycelium_test"
# Set test Redis URL
export TEST_REDIS_URL="redis://localhost:6379"
# Run tests
cargo test
Option 3: Using Test Containers
Mycelium supports testcontainers for automatic service provisioning:
# Tests will automatically start and stop required containers
cargo test --features testcontainers
Running Specific Tests
By Test Name
Run tests matching a pattern:
# Run all tests with "auth" in the name
cargo test auth
# Run all tests with "user_service" in the name
cargo test user_service
By Package
Run tests for a specific workspace package:
# Test the API package
cargo test -p mycelium-api
# Test the base package
cargo test -p mycelium-base
# Test all packages
cargo test --workspace
By Feature
Run tests for specific features:
# Test with all features enabled
cargo test --all-features
# Test without default features
cargo test --no-default-features
# Test with specific features
cargo test --features "vault,oauth2"
Test Output and Debugging
Verbose Output
See detailed test output:
cargo test -- --nocapture
Show Test Output (Even for Passing Tests)
cargo test -- --show-output
Run Tests in Single Thread (Useful for Debugging)
cargo test -- --test-threads=1
Enable Logging During Tests
RUST_LOG=debug cargo test -- --nocapture
Code Coverage
Generate code coverage reports using tarpaulin:
Install tarpaulin
cargo install cargo-tarpaulin
Generate Coverage Report
# Generate coverage and display in terminal
cargo tarpaulin --out Stdout
# Generate HTML coverage report
cargo tarpaulin --out Html
# Generate coverage for CI (Codecov, Coveralls)
cargo tarpaulin --out Xml
View Coverage Report
# Open HTML report
open tarpaulin-report.html # macOS
xdg-open tarpaulin-report.html # Linux
Benchmarking
Run performance benchmarks:
# Run all benchmarks
cargo bench
# Run specific benchmark
cargo bench routing_benchmark
Continuous Integration
Mycelium includes CI configurations for automated testing:
GitHub Actions
The repository includes GitHub Actions workflows that run on every push and pull request:
- Unit tests
- Integration tests
- Code coverage
- Linting (clippy)
- Formatting check
View workflow status:
# Check recent workflow runs
gh run list
# View specific run
gh run view <run-id>
Running CI Tests Locally
Simulate CI environment locally:
# Run all checks that CI runs
cargo fmt --check
cargo clippy -- -D warnings
cargo test --all-features
Test Database Management
Initialize Test Database
# Create test database
psql postgres://postgres:postgres@localhost:5432/postgres \
-c "CREATE DATABASE mycelium_test;"
# Run migrations
diesel migration run --database-url postgres://postgres:postgres@localhost:5432/mycelium_test
Reset Test Database
# Drop and recreate test database
psql postgres://postgres:postgres@localhost:5432/postgres \
-c "DROP DATABASE IF EXISTS mycelium_test;"
psql postgres://postgres:postgres@localhost:5432/postgres \
-c "CREATE DATABASE mycelium_test;"
# Run migrations again
diesel migration run --database-url postgres://postgres:postgres@localhost:5432/mycelium_test
Common Test Commands
Fast Test Cycle (Development)
# Run tests in watch mode (requires cargo-watch)
cargo install cargo-watch
cargo watch -x test
Pre-Commit Checks
# Run all checks before committing
cargo fmt --check && \
cargo clippy -- -D warnings && \
cargo test --all-features
Release Build Tests
# Test with release optimizations
cargo test --release
Test Organization
Mycelium tests are organized following Rust conventions:
mycelium/
├── src/
│ └── lib.rs # Unit tests in modules
├── tests/
│ ├── api_tests.rs # Integration tests
│ ├── auth_tests.rs
│ └── routing_tests.rs
└── benches/
└── routing_bench.rs # Benchmarks
Writing New Tests
Unit Test Example
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_user_creation() {
let user = User::new("test@example.com");
assert_eq!(user.email, "test@example.com");
}
#[tokio::test]
async fn test_async_operation() {
let result = async_function().await;
assert!(result.is_ok());
}
}
Integration Test Example
// tests/api_tests.rs
use mycelium_api::*;
#[tokio::test]
async fn test_health_endpoint() {
let app = setup_test_app().await;
let response = app.get("/health").await;
assert_eq!(response.status(), 200);
}
Troubleshooting
Tests Fail Due to Database Connection
Issue: Cannot connect to test database
Solution:
# Verify Postgres is running
pg_isready
# Check connection string
echo $TEST_DATABASE_URL
Tests Hang or Timeout
Issue: Tests hang indefinitely
Solution:
# Run with timeout
cargo test -- --test-threads=1 --timeout 30
Flaky Tests
Issue: Tests fail intermittently
Solution:
# Run tests multiple times to reproduce
for i in {1..10}; do cargo test test_name || break; done
Port Conflicts
Issue: Test services can’t bind to ports
Solution:
# Stop conflicting services
docker-compose down
killall myc-api
Test Best Practices
- Isolate tests: Each test should be independent
- Use test fixtures: Create reusable test data
- Clean up: Tests should clean up after themselves
- Mock external services: Use mocks for external dependencies
- Test edge cases: Don’t just test the happy path
- Keep tests fast: Optimize slow tests
- Use descriptive names: Test names should describe what they test
Next Steps
- Contributing Guidelines - Learn how to contribute
- Configuration Guide - Configure your development environment
- Authorization Model - Understand the security model
Additional Resources
- Rust Testing Guide
- Tokio Testing
- GitHub Issues - Report test failures