finance-query v3.0.0

Contributing#

We welcome contributions to FinanceQuery! This guide will help you get started.

warning · V1 (Python) is Not Maintained

The legacy Python implementation in /v1 is no longer actively maintained. All development focuses on the Rust library and server. The v1 source code, workflow, and documentation remain available for reference.

Quick Start#

Clone and set up the development environment:

bash
git clone https://github.com/Verdenroz/finance-query.git
cd finance-query
make install-dev  # Installs rustfmt, clippy, prek, sets up pre-commit hooks

This sets up prek (a faster Rust-based pre-commit) which runs fmt, clippy, and check automatically before each commit.

Useful Commands#

Run make help to see all available commands:

bash
make serve             # Start dev server (PORT=8000 by default)
make test              # Run ALL tests including network integration tests
make test-fast         # Run only fast tests (excludes network tests)
make fix               # Auto-fix formatting and clippy issues
prek                   # Run pre-commit checks (fmt, clippy, check)
make docs-pages        # Regenerate the derived docs pages
make docs              # Serve the docs site at localhost:8080
make build             # Build library and server in release mode
docker compose up -d   # Start the full stack (v1, v2, Redis, Caddy, monitoring)

Development Workflow#

1. Make Your Changes#

Work on the library (src/) or server (server/src/):

bash
# Start the dev server
make serve

# Run tests as you work
make test-fast  # Quick tests only
make test       # All tests including network calls

2. Check Your Code#

Before committing, run the pre-commit checks:

bash
make fix   # Auto-fix formatting and clippy issues
prek       # Verify all checks pass

3. Test Thoroughly#

Run the appropriate tests for your changes:

bash
# Library changes
cargo test -p finance-query

# Server changes
cargo test -p finance-query-server

# Specific test
cargo test test_ticker_quote

# Integration tests (makes real API calls)
cargo test -- --ignored

Code Standards#

Write Idiomatic Rust#

Use standard patterns and avoid unnecessary complexity:

rust · ignore
// Good - simple and clear
pub async fn quote(&self) -> Result<Quote> {
    self.get_quote_data().await
}

// Bad - over-engineered
pub async fn quote(&self) -> Result<Quote, Box<dyn std::error::Error>> {
    match self.get_quote_data().await {
        Ok(data) => Ok(data),
        Err(e) => Err(Box::new(e)),
    }
}

Document Public APIs#

Add doc comments to public items:

rust · ignore
/// Fetches the latest quote for the ticker.
///
/// # Example
///
/// ```no_run
/// use finance_query::{Raw, Ticker};
///
/// let ticker = Ticker::builder("AAPL").logo().build().await?;
/// let quote = ticker.quote::<Raw>().await?;
/// println!("Price: ${:.2}", quote.regular_market_price.unwrap_or(0.0));
/// ```
pub async fn quote(&self) -> Result<Quote> {
    // ...
}

Testing Guidelines#

Unit Tests#

Keep tests focused and fast:

rust · ignore
#[tokio::test]
async fn test_ticker_builder() {
    let ticker = Ticker::builder("AAPL")
        .region(Region::UnitedStates)
        .build()
        .await
        .unwrap();

    assert_eq!(ticker.symbol(), "AAPL");
}

Integration Tests#

Mark network tests with #[ignore]:

rust · ignore
use finance_query::format::Raw;

#[tokio::test]
#[ignore = "requires network access"]
async fn test_real_quote() {
    let ticker = Ticker::builder("AAPL").logo().build().await.unwrap();
    let quote = ticker.quote::<Raw>().await.unwrap();
    assert!(!quote.symbol.is_empty());
}

Doc Tests#

Use no_run for examples that require network access:

rust · ignore
/// # Example
///
/// ```no_run
/// # use finance_query::{Raw, Ticker};
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let ticker = Ticker::builder("AAPL").logo().build().await?;
/// let quote = ticker.quote::<Raw>().await?;
/// # Ok(())
/// # }
/// ```

Submitting Changes#

1. Create a Branch#

Use descriptive branch names:

bash
git checkout -b fix/quote-timezone-handling
git checkout -b feat/add-options-chain

2. Commit Your Changes#

Write clear commit messages:

bash
git add .
git commit -m "fix: handle timezone correctly in market hours"

3. Push and Create PR#

bash
git push origin fix/quote-timezone-handling

Open a pull request on GitHub with:

Common Tasks#

Adding a New Endpoint#

Library side:

  1. Add endpoint URL in src/endpoints/:
rust · ignore
    // src/endpoints/quote.rs
    pub fn options_chain(symbol: &str) -> String {
        format!("{}/v7/finance/options/{}", BASE_URL, symbol)
    }
  1. Define model in src/models/:
rust · ignore
    // src/models/options.rs
    #[derive(Debug, Clone, Deserialize)]
    pub struct OptionsChain {
        pub symbol: String,
        pub expiration_dates: Vec<i64>,
        // ...
    }
  1. Add method to Ticker:
rust · ignore
    // src/ticker/core.rs
    pub async fn options(&self) -> Result<OptionsChain> {
        let url = endpoints::options_chain(&self.symbol);
        self.client.fetch_json(&url).await
    }

Server side:

rust · ignore
// server/src/main.rs
async fn get_options(
    Path(symbol): Path<String>,
) -> Result<Json<OptionsChain>, AppError> {
    let ticker = Ticker::new(&symbol).await?;
    let options = ticker.options().await?;
    Ok(Json(options))
}

// Register route
.route("/v2/options/{symbol}", get(get_options))

Updating Dependencies#

Check for outdated dependencies:

bash
cargo outdated
cargo update
make test  # Ensure everything still works

Getting Help#

License#

By contributing, you agree that your contributions will be licensed under the MIT License.

built with cargo soothfast docs build source