Skip to content

Commit

Permalink
return dummy product
Browse files Browse the repository at this point in the history
  • Loading branch information
StuartHarris committed Dec 21, 2023
1 parent 4c447be commit 7bce034
Show file tree
Hide file tree
Showing 9 changed files with 1,825 additions and 5 deletions.
1,666 changes: 1,666 additions & 0 deletions rust-containers-k8s/product-service/Cargo.lock

Large diffs are not rendered by default.

13 changes: 12 additions & 1 deletion rust-containers-k8s/product-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,16 @@ version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.75"
axum = { version = "0.7.2", features = ["json", "macros", "query"] }
axum-extra = { version = "0.9.0", features = ["query"] }
dotenv = "0.15.0"
envy = "0.4.2"
reqwest = { version = "0.11.23", features = ["json"] }
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
tokio = { version = "1.35.0", features = ["full"] }
tower-http = { version = "0.5.0", features = ["trace"] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
43 changes: 43 additions & 0 deletions rust-containers-k8s/product-service/src/api/handlers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use axum::{extract::State, http::StatusCode, response::Result, Json};
use std::sync::Arc;

use super::{
server::AppState,
types::{Product, ProductRequest},
};

pub async fn root() -> &'static str {
"Hello, World!"
}

pub async fn health() -> &'static str {
"ok"
}

#[axum::debug_handler]
pub async fn get_all_products(State(_state): State<Arc<AppState>>) -> Result<Json<Vec<Product>>> {
Ok(Json(vec![Product {
id: 1,
name: "Product 1".to_string(),
description: "Product 1 description".to_string(),
price: 100,
sku_code: "SKU-1".to_string(),
}]))
}

#[axum::debug_handler]
pub async fn create_product(
State(_state): State<Arc<AppState>>,
Json(_payload): Json<ProductRequest>,
) -> Result<()> {
todo!()
}

/// Utility function for mapping any error into a `500 Internal Server Error`
/// response.
fn internal_error<E>(err: E) -> (StatusCode, String)
where
E: std::error::Error,
{
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}
3 changes: 3 additions & 0 deletions rust-containers-k8s/product-service/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod handlers;
pub mod server;
pub mod types;
39 changes: 39 additions & 0 deletions rust-containers-k8s/product-service/src/api/server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::{
api::handlers::{create_product, get_all_products, health, root},
config::Config,
};
use axum::{
routing::{get, post},
Router,
};
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::Arc,
};
use tokio::net::TcpListener;
use tower_http::trace::TraceLayer;

pub struct AppState {}

pub async fn create(config: Config) -> anyhow::Result<()> {
let state = Arc::new(AppState {});

let app = Router::new()
.route("/", get(root))
.route("/health", get(health))
.route("/api/product", post(create_product))
.route("/api/product", get(get_all_products))
.layer(TraceLayer::new_for_http())
.with_state(state);

let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), config.port);

let listener = TcpListener::bind(&socket).await.unwrap();

tracing::info!("listening on {}", socket);
axum::serve(listener, app.into_make_service())
.await
.unwrap();

Ok(())
}
19 changes: 19 additions & 0 deletions rust-containers-k8s/product-service/src/api/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProductRequest {
pub is_in_stock: bool,
pub sku_code: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Product {
#[serde(rename = "product_id")]
pub id: i64,
pub name: String,
pub description: String,
pub price: isize,
pub sku_code: String,
}
19 changes: 19 additions & 0 deletions rust-containers-k8s/product-service/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use serde::Deserialize;

#[derive(Deserialize, Debug)]
pub struct Config {
#[serde(default = "defaults::port")]
pub port: u16,
}

mod defaults {
pub const fn port() -> u16 {
8083
}
}

impl Config {
pub fn new() -> Result<Self, envy::Error> {
envy::from_env::<Config>()
}
}
2 changes: 2 additions & 0 deletions rust-containers-k8s/product-service/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod api;
pub mod config;
26 changes: 22 additions & 4 deletions rust-containers-k8s/product-service/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
use std::{thread, time::Duration};
use dotenv::dotenv;
use product_service::{api::server, config::Config};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

fn main() {
println!("Product service started");
thread::sleep(Duration::from_secs(60 * 60 * 24));
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
"product_service=info,tower_http=debug,axum::rejection=trace".into()
}),
)
.with(tracing_subscriber::fmt::layer())
.init();

dotenv().ok();
let config = Config::new().expect("Config couldn't be loaded");

tracing::info!("{:?}", config);

server::create(config).await?;

Ok(())
}

0 comments on commit 7bce034

Please sign in to comment.