navree

The facade and features

The navree crate: one dependency that re-exports every module, a prelude, one Cargo feature per module (full by default), and using a single crate on its own.

On this page

Introduction

Navree is split into small crates, but an app doesn't have to know that. The navree crate, the facade, is the one dependency an app needs: it re-exports every module crate, the attribute macros and a prelude of everyday names. Each module crate sits behind a Cargo feature of the same name, and all of them are on by default, so you can start with everything and trim later.

Depending on Navree

Cargo.toml

The crates aren't on crates.io yet, so the dependency comes from Git: cargo add --git https://github.com/NavreeHQ/navree navree adds it for you. An app created with navree new depends on a local checkout of Navree instead (a path dependency); see where new apps get Navree from.

main needs nothing else: AppBuilder::run starts its own Tokio runtime. Add tokio when you write #[tokio::test] tests, and add serde, sea-orm, garde or utoipa directly when you use their derives, because derive macros name their own crate.

Then one import brings the usual names into scope:

src/main.rs

What the facade contains

Every module crate is re-exported whole, as a module of the facade. navree::db::Uow is navree_db::Uow, the very same type.

PathCrateFeatureWhat it brings
navree::kernelnavree-kernelalwaysModule graph, DI container, lifecycle, commands
navree::contractsnavree-contractsalwaysCross-module traits: Principal, Job, Clock, AuditSink, ...
navree::confignavree-configalwaysConfigModule, .env, TOML and APP_* sources
navree::httpnavree-httphttpHttpModule, controllers, AppError
navree::lognavree-loglogLoggerModule
navree::cryptonavree-cryptocryptoCryptoModule: encryption, Argon2id hashing, the app key
navree::eventsnavree-eventseventsEventsModule: events and queued listeners
navree::viewnavree-viewviewViewModule: MiniJinja templates
navree::cachenavree-cachecacheCacheModule: cache stores and locks
navree::http_clientnavree-http-clienthttp-clientHttpClientModule: outgoing HTTP with fakes
navree::dbnavree-dbdbDatabaseModule: SeaORM, unit of work, migrations, pagination
navree::testingnavree-testingtestingTestApp, TestClient
navree::observenavree-observeobserveObserveModule: health checks and metrics
navree::apinavree-apiapiApiModule: OpenAPI document and docs UI
navree::mailnavree-mailmailMailModule: mailables, transports, queued mail
navree::realtimenavree-realtimerealtimeRealtimeModule: Pusher-protocol broadcasting
navree::storagenavree-storagestorageStorageModule: disks and uploads
navree::sessionnavree-sessionsessionSessionModule: cookie sessions and CSRF
navree::validationnavree-validationvalidationValid extractors on garde
navree::queuenavree-queuequeueQueueModule: database and memory job queues
navree::auditnavree-auditauditAuditModule: the audit trail
navree::accessnavree-accessaccessAccessModule: roles, permissions, CASL abilities
navree::schedulenavree-schedulescheduleScheduleModule: cron-style tasks
navree::notifynavree-notifynotifyNotifyModule: database, mail and broadcast notifications
navree::authnavree-authauthAuthModule: JWT access and refresh tokens, users

The facade's root also has:

  • The macros: navree::module, navree::injectable and navree::controller, with the route attributes get, post, put, patch and delete (which #[controller] consumes, so you don't import them).
  • The kernel types apps use most: Navree, App, AppBuilder, AppContext, Module, ModuleBuilder, ModuleId, Injectable, Factory, Lazy, Resolver, ProviderKey, Scope, KernelError, BoxError and BoxFuture.
  • navree::Result<T, E = AppError>, a handler's result type (with http).
  • navree::axum, Axum itself (with http), for the extractors and types navree-http doesn't re-export: navree::axum::extract::Request, navree::axum::http::HeaderMap, navree::axum::middleware::from_fn and so on.

The prelude

use navree::prelude::* brings the names almost every file uses. Each is there only when the feature of its crate is on:

GroupNames
StdArc
Macrosmodule, injectable, controller
KernelNavree, AppBuilder, AppContext, Module, ModuleBuilder, Injectable, Factory, Lazy, Resolver, BoxError
ConfigConfigModule, ConfigSources
HTTPResult, AppError, Json, Created, NoContent, Scoped, Path, Query, HttpModule
DatabaseDatabaseModule, Uow, Repo, Page, PageQuery, MigrationSet, ModelFactory
ValidationValid, ValidAsync, ValidationModule
AuthenticationAuthModule, AuthService, CurrentUser
AccessAccessModule, AccessOptions, Abilities, AbilityCtx, Accessible, Authorized, Rules, Subject, ActionMarker, field, the action markers Read, Create, Update, Delete, Manage and the constants READ, CREATE, UPDATE, DELETE, MANAGE, ALL
Other modulesLoggerModule, CryptoModule, EventsModule, ViewModule, CacheModule, HttpClientModule, ApiModule, MailModule, ObserveModule, RealtimeModule, StorageModule, SessionModule, QueueModule, AuditModule, ScheduleModule, NotifyModule

It also imports every ModuleBuilder extension trait anonymously (as _), so methods such as m.config::<T>(), m.controller::<C>(), m.migrations(..), m.job::<J>(), m.listen::<E, L>(), m.templates(..) and m.schedule(..) work without naming the traits.

Three details to know:

  • Result is Navree's. With http, the prelude's Result<T> is navree::Result<T>, whose error type defaults to AppError, and it shadows the standard prelude's Result. Name the error type when it isn't an AppError: fn main() -> Result<(), BoxError>.
  • Two factories. Factory is the kernel's provider factory. navree-db's model factory trait (for test data) is renamed ModelFactory in the prelude.
  • Test helpers aren't in the prelude. Import them from navree::testing.

Cargo features

The facade has one feature per module crate, named after it (http-client for navree::http_client). The default feature, full, turns on all of them. To build only what you use, turn the defaults off and list the modules:

Cargo.toml

navree-kernel, navree-contracts, navree-config and navree-macros are always included. A module's feature also turns on the features of the modules its crate builds on, so navree::<that module> is always there to name their types:

FeatureAlso turns on
http, log, crypto, events, view, cache, http-clientNothing else (and http adds navree::axum)
db, testing, observe, apihttp
mailview
realtime, storagehttp, crypto
sessionhttp, crypto, db
validation, audit, accesshttp, db
queue, scheduledb
notifyhttp, db, mail
authhttp, db, crypto, validation, cache, mail, access
postgresdb, and navree-db's PostgreSQL driver

SQLite is always available with db. The postgres feature adds the PostgreSQL driver. The benchmark runs Navree on PostgreSQL 17, but the test suite runs on SQLite only, so some PostgreSQL-only code paths haven't been run yet. The database pages list which.

Tests in crates/navree/tests/facade.rs keep this table true: every module crate sits behind a feature named after it, each module feature turns on exactly the features of the crates its crate depends on (no fewer, no more), and full is the default and covers every module.

How the macros find the crates

#[module], #[injectable] and #[controller] expand into code that calls the runtime crates. They look in your Cargo.toml to decide how to name them:

  1. If the crate depends on navree, the code names ::navree::kernel, ::navree::http and ::navree::access. A renamed dependency is honoured: with framework = { package = "navree", git = "https://github.com/NavreeHQ/navree" }, the code names ::framework::kernel.
  2. Otherwise it names the individual crates: ::navree_kernel, ::navree_http, ::navree_access.
  3. If neither is there, the attribute fails to compile with: this attribute needs the `navree` crate (or `navree-kernel`) in the [dependencies] of your Cargo.toml.

#[controller] needs navree-http, and #[can] with marker types such as #[can(Update, Deal)] needs navree-access; with the facade, that means the http and access features.

Using a crate on its own

Every module crate is a normal library you can depend on directly, without the facade. The kernel alone gives you modules, dependency injection, lifecycle hooks and commands:

Rust

The macros work with the individual crates too. This is the greeting app without the facade:

Cargo.toml
src/main.rs

You give up the prelude and the single version to keep in step, so the facade with default-features = false is usually the better way to build a small app. Depending on one crate directly makes sense for a library that extends one module, such as a new cache store or authentication strategy: it then depends only on the crates it extends.

Popular pages

  • Installation
  • Your first app
  • Routing and controllers
  • Validation
  • Authentication
  • Benchmarks