CI / test (push) Canceled after 0s
Covers Clients, Invoices, Quotes, Credits, Payments, Products, Expenses, Projects, Tasks, and Vendors, each with list, list_all, get, create, update, and delete, generated by the resource_methods! macro. Every model carries a #[serde(flatten)] extra map so fields the API returns but the crate does not model survive a get/update round-trip instead of being silently dropped. Includes a Nix dev shell (Rust via rust-overlay), a GitHub Actions CI workflow running build/test/fmt/clippy, and round-trip tests for the extra-preservation invariant. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.0 KiB
3.0 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this is
An async Rust client for the Invoice Ninja v5 API.
Development environment
This project uses Nix for toolchain management (Rust via rust-overlay):
nix develop
Common commands
cargo build
cargo test
cargo test <test_name> # run a single test
cargo check
cargo clippy
cargo fmt
# Run the example (requires IN_API_TOKEN, optionally IN_BASE_URL)
IN_API_TOKEN=... cargo run --example list_clients
Tests live in tests/ (integration-style, no network access required);
src/ has no #[test] modules.
Architecture
src/client.rs—InvoiceNinjaClientholds areqwest::Client(with theX-Api-Tokenauth header baked in) and abase_url. Low-level helpers (get_list,get_one,post_one,put_one,delete_one) handle request dispatch and decodeListResponse<T>/ItemResponse<T>envelopes, mapping non-2xx responses throughapi_errorintoError::Api.- Per-resource methods (
list_clients,get_invoice,create_product, etc.) are generated by theresource_methods!macro at the bottom ofclient.rs, which expands tolist/list_all/get/create/update/deletefor a given REST path and model type. To add a new resource: add a model undersrc/models/, re-export it fromsrc/models/mod.rs, and add oneresource_methods!invocation inclient.rs. Note the macro takes six method names before the path and model — adding a resource means passing all six. list_*returns one page;list_all_*goes throughget_all_pages, which followspage/per_pageuntil a page returns fewer rows than requested.src/models/— one file per resource (client.rs,invoice.rs,payment.rs,product.rs,expense.rs,project.rs,task.rs,vendor.rs), pluscommon.rsfor shared envelope/pagination types (ListParams,ListResponse,ItemResponse,Meta,Pagination). Invoice Ninja stores quotes and credits in the same table as invoices (anentity_typefield distinguishes them), soQuoteandCreditare type aliases forInvoice(src/models/invoice.rs) and share the/quotes,/credits, and/invoicespaths via the macro.- Every model struct has a
#[serde(flatten)] pub extra: Map<String, Value>field. This preserves any API fields not explicitly modeled, so agetfollowed by anupdateround-trips without silently dropping data. Keep this pattern when adding fields or new models. src/error.rs—Errorenum (thiserror) covering transport, JSON decode, API error responses (with per-field validationerrorsmap), and client construction errors.ApiErrorBodymirrors Invoice Ninja's error JSON shape.
Coverage
Clients, Invoices, Quotes, Credits, Payments, Products, Expenses, Projects,
Tasks, and Vendors, each with list, list_all, get, create, update,
and delete.