From 7a370b50d75a20253f82ae005761c947000d45e2 Mon Sep 17 00:00:00 2001 From: Pedro Martin Date: Tue, 19 Dec 2023 16:31:15 +0000 Subject: [PATCH] Draft handller for POST /order --- .../order-service/src/api/handlers.rs | 63 +++++++++++++++++++ .../order-service/src/api/server.rs | 34 ++++++---- rust-containers-k8s/order-service/src/main.rs | 10 ++- 3 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 rust-containers-k8s/order-service/src/api/handlers.rs diff --git a/rust-containers-k8s/order-service/src/api/handlers.rs b/rust-containers-k8s/order-service/src/api/handlers.rs new file mode 100644 index 0000000..83f9034 --- /dev/null +++ b/rust-containers-k8s/order-service/src/api/handlers.rs @@ -0,0 +1,63 @@ +use super::server::AppState; +use crate::api::types::{InventoryResponse, OrderRequest}; +use axum::{debug_handler, extract::State, http::StatusCode, Json}; +use std::sync::Arc; + +pub async fn root() -> &'static str { + "Hello, World!" +} + +pub async fn get_orders() -> &'static str { + "Hello, World!" +} + +#[debug_handler] +pub async fn create_order( + State(state): State>, + Json(payload): Json, +) -> Result<(), (StatusCode, String)> { + let query: Vec<(String, String)> = payload + .items + .iter() + .map(|i| ("sku".to_string(), i.sku.clone())) + .collect(); + // call inventory service; + // takes a request of a list of order line items, checks they are all in stock (http call to the inventory service) and if so, creates an order entry in the database + let client = reqwest::Client::new(); + let all_in_stock = client + // TODO: update this url + .get("http://inventory-service/api/inventory") + .query(&query) + .send() + .await + .map_err(internal_error)? + .json::>() + .await + .map_err(internal_error)? + .iter() + .all(|i| i.is_in_stock); + + if all_in_stock { + // TODO: Update SQL query + let row: (i64,) = sqlx::query_as("INSERT into sometable values ($1)") + .bind(150_i64) + .fetch_one(&state.pool) + .await + .map_err(internal_error)?; + } + + Ok(()) +} + +/// Utility function for mapping any error into a `500 Internal Server Error` +/// response. +fn internal_error(err: E) -> (StatusCode, String) +where + E: std::error::Error, +{ + (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) +} + +pub async fn health() -> &'static str { + "ok" +} diff --git a/rust-containers-k8s/order-service/src/api/server.rs b/rust-containers-k8s/order-service/src/api/server.rs index b52ff3e..da0d3af 100644 --- a/rust-containers-k8s/order-service/src/api/server.rs +++ b/rust-containers-k8s/order-service/src/api/server.rs @@ -1,21 +1,29 @@ -use axum::{routing::get, Router}; - +use crate::api::handlers::{create_order, get_orders, health, root}; use crate::config::Config; +use axum::{routing::get, routing::post, Router}; +use sqlx::{Pool, Postgres}; +use std::sync::Arc; + +pub struct AppState { + pub pool: Pool, +} + +pub async fn create(config: Config, pool: Pool) -> anyhow::Result<()> { + let state = Arc::new(AppState { pool }); -pub async fn create(config: Config) { // build our application with a route - let app = Router::new().route("/", get(root)); + let app = Router::new() + .route("/", get(root)) + .route("/health", get(health)) + .route("/api/order", get(get_orders)) + .route("/api/order", post(create_order)) + .with_state(state); // run it //todo pass a port - let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", config.port)) - .await - .unwrap(); - println!("listening on {}", listener.local_addr().unwrap()); - axum::serve(listener, app).await.unwrap(); -} + let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", config.port)).await?; + println!("listening on {}", listener.local_addr()?); + axum::serve(listener, app).await?; -// basic handler that responds with a static string -async fn root() -> &'static str { - "Hello, World!" + Ok(()) } diff --git a/rust-containers-k8s/order-service/src/main.rs b/rust-containers-k8s/order-service/src/main.rs index 101b783..cf77b4b 100644 --- a/rust-containers-k8s/order-service/src/main.rs +++ b/rust-containers-k8s/order-service/src/main.rs @@ -1,5 +1,6 @@ use dotenv::dotenv; use order_service::{api::server, config::Config}; +use sqlx::postgres::PgPoolOptions; #[tokio::main] async fn main() -> Result<(), Box> { @@ -8,7 +9,12 @@ async fn main() -> Result<(), Box> { println!("{:?}", config); - server::create(config).await; + let pool = PgPoolOptions::new() + .max_connections(5) + // TODO: paramterise this + .connect("postgres://commerce:commerce@localhost/order-service") + .await?; + + server::create(config, pool).await?; Ok(()) } -