Introduction
5-Minute Quickstart
Get a microservice running in 5 minutes with automatic health checks and observability.
Prerequisites
- Rust 1.70+ installed
- Basic familiarity with async Rust
- 5 minutes of your time
Step 1: Create a New Project (30 seconds)
cargo new my-api
cd my-api
Step 2: Add Dependencies (30 seconds)
Add acton-service to your Cargo.toml:
[dependencies]
Step 3: Write Your First Service (2 minutes)
Replace the contents of src/main.rs:
use acton_service::prelude::*;
// Your first handler
async fn hello() -> &'static str {
"Hello from acton-service!"
}
#[tokio::main]
async fn main() -> Result<()> {
// Build versioned routes - versioning is enforced!
let routes = VersionedApiBuilder::new()
.with_base_path("/api")
.add_version(ApiVersion::V1, |router| {
router.route("/hello", get(hello))
})
.build_routes();
// Build and serve - config and tracing are automatic!
ServiceBuilder::new()
.with_routes(routes)
.build()
.serve()
.await
}
Step 4: Run It! (30 seconds)
cargo run
You should see:
Compiling my-api v0.1.0
Finished dev [unoptimized + debuginfo] target(s)
Running `target/debug/my-api`
Step 5: Test It! (1 minute)
Open another terminal and test your endpoints:
# Your versioned API
curl http://localhost:8080/api/v1/hello
# Output: Hello from acton-service!
# Automatic health check (for Kubernetes)
curl http://localhost:8080/health
# Output: {"status":"healthy"}
# Automatic readiness check
curl http://localhost:8080/ready
# Output: {"status":"ready"}
What Just Happened?
You created a microservice with these features enabled by default:
✅ Type-enforced API versioning - Compiler prevents unversioned routes
✅ Automatic health checks - /health and /ready endpoints for Kubernetes
✅ Automatic logging - Structured JSON logs
✅ Automatic tracing - OpenTelemetry tracing configured
✅ Graceful shutdown - Signal handling (SIGTERM, SIGINT)
✅ Default configuration - Works with sensible defaults
What's Next?
Add More Endpoints
async fn get_user(Path(id): Path<u64>) -> Json<serde_json::Value> {
Json(serde_json::json!({
"id": id,
"name": "Alice"
}))
}
// Add to your router:
.add_version(ApiVersion::V1, |router| {
router
.route("/hello", get(hello))
.route("/users/{id}", get(get_user)) // New!
})
Add a Second Version
// V2 with improved response
async fn hello_v2() -> Json<serde_json::Value> {
Json(serde_json::json!({
"message": "Hello from V2!",
"version": "2.0"
}))
}
// Add V2 to your routes:
.add_version(ApiVersion::V1, |router| {
router.route("/hello", get(hello))
})
.add_version(ApiVersion::V2, |router| {
router.route("/hello", get(hello_v2)) // New version!
})
Try the Examples
The repository includes comprehensive examples:
# Clone the repo
git clone https://github.com/Govcraft/acton-service
cd acton-service
# Run the simple API example
cargo run --manifest-path=acton-service/Cargo.toml --example simple-api
# Run the users API example (shows deprecation)
cargo run --manifest-path=acton-service/Cargo.toml --example users-api
# Run the dual HTTP+gRPC example
cargo run --manifest-path=acton-service/Cargo.toml --example ping-pong --features grpc
Common First Questions
Q: Why can't I just use Router::new()? A: acton-service enforces versioning at compile time. All routes must be versioned to prevent breaking changes from slipping into production.
Q: How do I add middleware? A: See the Tutorial for middleware examples.
Q: How do I connect to a database? A: Add the database feature and see the Tutorial.
Q: Can I disable versioning? A: No. If you need unversioned routes, use Axum directly. acton-service is opinionated about API evolution.
Next Steps
- Tutorial - Step-by-step guide to building a real service
- Feature Flags - Understand which features you need
- Examples - Complete working examples
- Configuration - Full configuration guide
Need Help?
You're now ready to explore acton-service features.