Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions iad/todos/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

/target
.shuttle*
Secrets*.toml
13 changes: 13 additions & 0 deletions iad/todos/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "todos"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.8"
serde = { version = "1", features = ["derive"] }
shuttle-axum = "0.57.0"
shuttle-runtime = "0.57.0"
shuttle-shared-db = { version = "0.57.0", features = ["postgres", "sqlx"] }
sqlx = "0.8"
tokio = "1.28.2"
36 changes: 36 additions & 0 deletions iad/todos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Todo API - Infrastructure as Data with Shuttle

A Rust-based Todo API demonstrating **Shuttle's Infrastructure as Data (IaD)** approach. This project showcases how Shuttle provisions and manages infrastructure resources through simple function annotations, eliminating the need for complex configuration files or manual cloud setup.

## What is Infrastructure as Data?

**Infrastructure as Data (IaD)** is Shuttle's approach to infrastructure provisioning where you declare your infrastructure needs directly in your code using Rust attributes. Instead of writing YAML files, Terraform scripts, or clicking through cloud consoles, you simply annotate your function parameters, and Shuttle handles the rest.

### Key Benefits

- **No Configuration Files**: Infrastructure defined in code, not YAML or JSON
- **Type-Safe**: Leverage Rust's type system for infrastructure
- **Automatic Provisioning**: Resources created on deployment
- **Zero DevOps**: No manual cloud console configuration
- **Instant Local Development**: Same code works locally and in production

## Infrastructure as Data in Action

This project demonstrates IaD with a PostgreSQL database:

```rust
#[shuttle_runtime::main]
async fn main(
#[shuttle_shared_db::Postgres] pool: PgPool
) -> shuttle_axum::ShuttleAxum {
// Your database is ready to use!
}
```

**That's it!** With just one annotation (`#[shuttle_shared_db::Postgres]`), Shuttle:
1. ✅ Provisions a PostgreSQL database
2. ✅ Configures connection credentials
3. ✅ Injects a connection pool into your app
4. ✅ Manages the database lifecycle

No environment variables, no connection strings, no manual setup.
6 changes: 6 additions & 0 deletions iad/todos/migrations/0001_init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS todos (
id serial PRIMARY KEY,
note TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
completed BOOLEAN NOT NULL DEFAULT FALSE
);
77 changes: 77 additions & 0 deletions iad/todos/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use axum::{
extract::{Path, State},
http::StatusCode,
response::IntoResponse,
routing::{get, post},
Json, Router,
};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};

async fn retrieve(
Path(id): Path<i32>,
State(state): State<MyState>,
) -> Result<impl IntoResponse, impl IntoResponse> {
match sqlx::query_as::<_, Todo>("SELECT * FROM todos WHERE id = $1")
.bind(id)
.fetch_one(&state.pool)
.await
{
Ok(todo) => Ok((StatusCode::OK, Json(todo))),
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
}
}

async fn add(
State(state): State<MyState>,
Json(data): Json<TodoNew>,
) -> Result<impl IntoResponse, impl IntoResponse> {
match sqlx::query_as::<_, Todo>(
"INSERT INTO todos (note) VALUES ($1) RETURNING id, note, description, completed",
)
.bind(&data.note)
.bind(&data.description)
.bind(data.completed)
.fetch_one(&state.pool)
.await
{
Ok(todo) => Ok((StatusCode::CREATED, Json(todo))),
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
}
}

#[derive(Clone)]
struct MyState {
pool: PgPool,
}

#[shuttle_runtime::main]
async fn main(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_axum::ShuttleAxum {
sqlx::migrate!()
.run(&pool)
.await
.expect("Failed to run migrations");

let state = MyState { pool };
let router = Router::new()
.route("/todos", post(add))
.route("/todos/{id}", get(retrieve))
.with_state(state);

Ok(router.into())
}

#[derive(Deserialize)]
struct TodoNew {
pub note: String,
pub description: String,
pub completed: bool,
}

#[derive(Serialize, FromRow)]
struct Todo {
pub id: i32,
pub note: String,
pub description: String,
pub completed: bool,
}
4 changes: 4 additions & 0 deletions iad/upload-manager/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

/target
.shuttle*
Secrets*.toml
16 changes: 16 additions & 0 deletions iad/upload-manager/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "upload-manager"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.8"
shuttle-axum = "0.57.0"
shuttle-runtime = "0.57.0"
shuttle-aws-rds = { version = "0.57.0", features = ["postgres"] }
tokio = { version = "1.28.2", features = ["full"] }
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres", "chrono", "uuid"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1.0", features = ["serde", "v4"] }
Loading