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:
wasm-bindgen
cargo-bench
scaffolding (optional)arm64
, amd64
), buildx-focused
Dockerfiles—pick a musl
or glibc
build—for binary
executables (right now), as well as an associated GitHub Action for building
and pushing to GitHub Packages Registry and
Docker Hub.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, and thiserror
for designing
dedicated error type(s) in libraries so that on failures the caller gets
exactly the information chosen.proptest
and criterion
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.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:
Template-specific extensions to axum
, including
Unprocessable Entity
responses.AppError
type for encoding JSONAPI error object responses.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);
}
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.Ctrl-c
'ed or terminated.config-rs
for layered configuration settings and using
APP
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
and axum-tracing-opentelemetry
for integrating axum
and tracing
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 displaying OTEL
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
and criterion
for generating inputs and
running benchmarks (optional).reqwest
as the default HTTP client library and
reqwest-middleware
as a wrapper around reqwest
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 Procedural attribute 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 choosing axum
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 like window.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 run direnv allow
and add your files via git 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:
:balloon: 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.
pre-commit install
and pre-commit install --hook-type commit-msg
to setup the pre-commit hooks locally. This will reduce failed CI builds.git commit -a -m "Your message here" --no-verify
.Major shout-outs to the various contributors of this work, including:
This project is licensed under either of
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.