This template repository is Fission's opinionated Rust, Rust web framework, and Rust+WebAssembly (Wasm) project generator, which uses the cargo-generate tool.
These templates provide various features for getting-up and running with Rust or Rust and Wasm, including:
- README standardization, code of conduct, contribuing guidelines, and a consistent project layout
- GitHub issue and pull-request templates
- A highly-opinionated axum middleware-extensive webserver, focused heavily on observability and flexibility
- Some choice default Rust dependencies (particularly for Wasm) including
wasm-bindgen
cargo-bench
scaffolding (optional)- Release GitHub Action workflow(s) using the
release-please-action and the
release-please deploy strategy (optional)
- For Wasm libraries, this includes publishing to npm with wasm-pack, reliant on the Cargo version for the Wasm package.
- Test, lint, audit, and code coverage (via Codecov) GitHub Action workflows (optional)
- Cross-compile-compatible (
arm64
,amd64
), buildx-focused Dockerfilesβpick amusl
orglibc
buildβfor binary executables (right now), as well as an associated GitHub Action for building and pushing to GitHub Packages Registry and Docker Hub. - Pre-commit and rustfmt opinionated defaults
- Dependabot support (optional)
- Nix flake support (optional)
- A choice of an Apache, MIT, or a dual Apache/MIT license
This repository contains two sub-templates:
rust
: for generating a rust-only library, webserver, or binary/executable project.rust+wasm
for generating a cargo workspace with a rust-only crate of the project (library or binary) and another crate for wasm-bindings (library-only), meant for execution in Node.js or running in modern browsers and/or with bundlers like webpack.
First, install cargo-generate via cargo install cargo-generate
.
More installation options are available here.
The experience running through the experience should look something like this:
The rust
template is designed for generating a rust binary or application
library.
-
Generate a binary project, for example an axum webserver:
cargo generate --bin --git https://github.com/fission-codes/rust-template
Note on binary crate types: If using the --bin
flag, this template will
generate a Rust binary project scaffolding with both a src/main.rs
and a
src/lib.rs
. This allows for better support for
integration testing and helps with
separation of concerns.
-
Generate an application library project:
cargo generate --lib --git https://github.com/fission-codes/rust-template
-
Generate a project from src, locally:
cargo generate --lib --path fission-codes/rust-template/
Note on SSH-Keys: When genearting a project/repository, please be aware
that RSA keys used with SHA-1 signatures are no longer supported by
GitHub. There is currently an issue in the
cargo-generate
repository involving an id_rsa
default. If you run into an
associated error using the template, please specify your private key when
generating a project/repository like so:
cargo generate -i ~/.ssh/id_ed25519 https://github.com/fission-codes/rust-template
anyhow
as a ergonomic and idiomatic alternative for handling errors in applications, andthiserror
for designing dedicated error type(s) in libraries so that on failures the caller gets exactly the information chosen.proptest
andcriterion
for generating inputs and running benchmarks (optional).tracing
for instrumenting Rust programs to collect structured, event-based diagnostic information, going beyond just logging-style diagnostics.tracing-subscriber
for Rust binary applications to collect trace data, such as by logging it to standard output, and consume messages emitted by log-instrumented libraries and modules.- An option to generate a highly opiniated
axum
web application stack.
If you choose to run a webserver with axum
(choosing true
at the
prompt), you'll be given an extensive web framework to work from, heavily
influenced by Composing an observable Rust application,
among other sources.
-
anyhow
as a ergonomic and idiomatic alternative for handling errors in applications. -
axum
as the fundamenal, already-π's included web framework that serves as our foundation, which includes high-level features like:- Routing requests to handlers with a macro free API
- Declaratively parsing requests using extractors.
- Subscribing to a simple and predictable error handling model, which we further simplify in our generated template.
- Generating responses with minimal boilerplate.
- Taking full advantage of the tower and tower-http ecosystem of middleware, services, and utilities.
-
Template-specific extensions to
axum
, including-
An enhanced Json extractor for better handling of
Unprocessable Entity
responses. -
A generic
AppError
type for encoding JSONAPI error object responses. -
A macro for generating typed HTTP headers, for example
header!(XDummyId, XDUMMY_ID, "x-dummy-id"); fn test_dummy_header() { let s = "18312349-3139-498C-84B6-87326BF1F2A7"; let dummy_id = test_decode::<XDummyId>(&[s]).unwrap(); let headers = test_encode(dummy_id); assert_eq!(headers["x-dummy-id"], s); }
-
Built-in
healthcheck
,ping
GET route handlers, as well as a fallback route handler and decorated layers for catching panics, handling server timeouts, setting ulid request-ids per request, and marking sensitive headers on both requests and responses. -
Graceful shutdown of server when
Ctrl-c
'ed or terminated.
-
-
config-rs
for layered configuration settings and usingAPP
prefixed environment variables for (overrding) configuration.We provide a default for application settings (note: metrics and server ports are provided through
cargo generate
prompts):[monitoring] process_collector_interval = 10 [otel] exporter_otlp_endpoint = "http://localhost:4317" [server] environment = "local" metrics_port = 4000 port = 3000 timeout_ms = 30000
-
metrics-rs
for application instrumentation, including counters, gauges, histograms, and more. -
opentelemetry-rust
andaxum-tracing-opentelemetry
for integratingaxum
andtracing
with opentelemetry, the well-known observability framework and specification for capturing telemetry data and supporting distributed tracing context propagation. Here's an example set of logs displayingOTEL
spec fields, among other contextual information:level=INFO span_name="HTTP request" span=2251799813685249 span_event=new_span timestamp=2023-01-29T15:06:42.188395Z http.method=GET http.client_ip=127.0.0.1:59965 http.host=localhost:3000 trace_id=fa9754fa3142db2c100a8c47f6dd391d http.route=/ping level=INFO subject=request category=http.request msg="started processing request" request_path=/ping authorization=null target="project::middleware::logging" location="project/src/middleware/logging.rs:123" timestamp=2023-01-29T15:06:42.188933Z span=2251799813685249 otel.name="GET /ping" http.method=GET http.scheme=HTTP http.client_ip=127.0.0.1:59965 http.flavor=1.1 otel.kind=server http.user_agent=curl/7.85.0 http.host=localhost:3000 trace_id=fa9754fa3142db2c100a8c47f6dd391d http.target=/ping http.route=/ping level=INFO span_name="HTTP request" span=2251799813685249 span_event=close_span timestamp=2023-01-29T15:06:42.192221Z http.method=GET latency_ms=3 http.client_ip=127.0.0.1:59965 http.host=localhost:3000 trace_id=fa9754fa3142db2c100a8c47f6dd391d http.route=/ping
-
proptest
andcriterion
for generating inputs and running benchmarks (optional). -
reqwest
as the default HTTP client library andreqwest-middleware
as a wrapper aroundreqwest
for client middleware chaining, giving us retries and tracing out of the box. -
sysinfo
for monitoring process information like memory, disk usage, etc. This information is automatically represented and tracked as gauges for Prometheus scraping/export for example. -
tracing
for instrumenting Rust programs to collect structured, event-based diagnostic information, going beyond just logging-style diagnostics. -
tracing-subscriber
for Rust binary applications to collect trace data, such as by logging it to standard output, and to consume messages emitted by log-instrumented libraries and modules.For
axum
projects, we include a compositon of tracing subscribers from smaller units of behavior, called layers, for collecting, augmenting, and logging (as structured logs) trace data. These layers tap into hooks triggered throughout a spanβs lifecycle. You can find them here.Event logs are formatted in
logfmt
, as a series of key/value pairs. The implementation of the log generation is inspired by influxdata's (Influx DB's) version. -
utoipa
for compile-time, auto-generated OpenAPI documentation and serving it via Swagger UI. This works as a Proceduralattribute macro
, for example:#[utoipa::path( get, path = "/ping", responses( (status = 200, description = "Ping successful"), (status = 500, description = "Ping not successful", body=AppError) ) )] pub async fn get() -> AppResult<StatusCode> { Ok(StatusCode::OK) }
-
wiremock-rs
to provide HTTP mocking to perform black-box testing of Rust applications that interact with third-party client APIs. This is exemplified through the given integration test when choosingaxum
as a prompt.
The rust+wasm
template is designed for generating a workspace
containing both rust-native library or binary code, as well a library for
compilation to Wasm and leveraging wasm-pack. We don't currently
support any Javascript examples or frameworks that can use Wasm npm package
explicitly, but this is on our radar. Additionally, when using the --bin
flag
you have the option to generate our axum template with
all the π's mentioned above.
Generate a project just like before and choose the rust+wasm
template:
cargo generate --lib --git https://github.com/fission-codes/rust-template
Note: Currently, wasm-pack
does not support building binary
crates, so even with the --bin
flag specified, a library
will still be generated.
wasm-bindgen
for communicating between WebAssembly and JavaScript.wasm-bindgen-futures
for converting between Javascript Promises and Rust futures.console_error_panic_hook
for logging panic messages to the developer console.js-sys
for bindings to Javascript's standard, built-in objects.web-sys
for bindings to Web APIs likewindow.fetch
, WebGL, WebAudio, etc. (optional, via feature-flag).
The generator is also designed for templating within an existing project and prompts with this in mind. To generate in an existing project, run this command in the project root:
cargo generate --git https://github.com/fission-codes/rust-template --init
When taking this approach, please be aware that some of the generated code, e.g. benches, READMEs, etc., rely on dependencies or contain text that may not be set in or follow the layout of your existing Rust codebase, so please make the appropriate changes where needed.
If the generator detects a conflict, it will not alter your project in any way, failing with an error. We can't cover all the cases when extending an existing project. If you run into problems, open an issue.
-
If using
nix
via Nix flake, please install nix and direnv to get started. Then, make sure to rundirenv allow
and add your files viagit add
. -
If Codecov upload is enabled through GitHub Actions make sure to sync your project and gather tokens/badges. Read more here.
-
There are stock integration tests available for all templates, including a wasm-bindgen decorated test,
#[wasm_bindgen_test]
, that can be tested with wasm-pack. -
For CI/CD purposes, be aware there's some secrets you'll need to configure in Github, including:
π We're thankful for any feedback and help in improving our template generator! We have a contributing guide to help you get involved. We also adhere to Fission's Code of Conduct.
This repository recommends using pre-commit for running pre-commit hooks. Please run this before every commit and/or push.
- Once installed, Run
pre-commit install
andpre-commit install --hook-type commit-msg
to setup the pre-commit hooks locally. This will reduce failed CI builds. - If you are doing interim commits locally, and for some reason if you don't
want pre-commit hooks to fire, you can run
git commit -a -m "Your message here" --no-verify
.
Major shout-outs to the various contributors of this work, including:
- @bgins
- @BoisterousCoder
- @QuinnWilton
- @expede
- @pauljamescleary
- @drunkirishcoder
- @jaredmorrow
- @glitchy
- @jwhittle933
- @walkah
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.