diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 535436a..283e3e4 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -52,7 +52,7 @@ // cargo-shuttle port 8000, // standalone port - 3000 + 8080 ], // Use 'postCreateCommand' to run commands after the container is created. diff --git a/Cargo.lock b/Cargo.lock index 4558e5d..6545522 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1298,6 +1298,7 @@ dependencies = [ "axum 0.7.2", "bson", "chrono", + "futures", "http-body-util", "mockall", "mongodb", @@ -1314,6 +1315,7 @@ version = "0.1.0" dependencies = [ "axum 0.7.2", "link-for-later", + "mongodb", "tokio", "tower", "tracing", diff --git a/link-for-later-axum/Cargo.toml b/link-for-later-axum/Cargo.toml index aabc9d7..6161e7b 100644 --- a/link-for-later-axum/Cargo.toml +++ b/link-for-later-axum/Cargo.toml @@ -11,6 +11,7 @@ publish = false [dependencies] axum = "0.7.2" link-for-later = { path = "../link-for-later" } +mongodb = "2.8.0" tokio = { version = "1", features = ["macros"] } tower = "0.4.13" tracing = { version = "0.1", features = ["log"] } diff --git a/link-for-later-axum/README.md b/link-for-later-axum/README.md index c862437..bb282c8 100644 --- a/link-for-later-axum/README.md +++ b/link-for-later-axum/README.md @@ -2,10 +2,14 @@ ## Development -Use `cargo run`: +The standalone server is using a MongoDb repository. + +Set the MongoDB server and database name. Then use `cargo run` to run the Server. ```sh +export MONGODB_URI="mongodb://localhost:23288" +export MONGODB_DATABASE_NAME="test" cargo run --bin link-for-later-axum ``` -You will be able to send requests to the server using port 3000. +You will be able to send requests to the server using port 8080. diff --git a/link-for-later-axum/src/main.rs b/link-for-later-axum/src/main.rs index 601e39e..ddf0264 100644 --- a/link-for-later-axum/src/main.rs +++ b/link-for-later-axum/src/main.rs @@ -1,3 +1,5 @@ +use mongodb::{options::ClientOptions, Client}; + #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt() @@ -8,9 +10,16 @@ async fn main() -> Result<(), Box> { .without_time() .init(); - let app = link_for_later::app::new(link_for_later::RepositoryType::None); + let uri = std::env::var("MONGODB_URI")?; + let database_name = std::env::var("MONGODB_DATABASE_NAME")?; + + let client_options = ClientOptions::parse(uri).await?; + let client = Client::with_options(client_options)?; + let db = client.database(&database_name); + + let app = link_for_later::app::new(link_for_later::RepositoryType::MongoDb(db)); - let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?; + let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?; axum::serve(listener, app).await.unwrap(); Ok(()) } diff --git a/link-for-later/Cargo.toml b/link-for-later/Cargo.toml index dad76bb..1b16139 100644 --- a/link-for-later/Cargo.toml +++ b/link-for-later/Cargo.toml @@ -10,6 +10,7 @@ publish = false axum = "0.7.2" bson = "2.8.1" chrono = { version = "0.4.31", default-features = false, features=["clock", "serde"] } +futures = "0.3.29" http-body-util = "0.1.0" mongodb = "2.8.0" serde = { version = "1.0.193", features = ["derive"] } diff --git a/link-for-later/src/repository/mongodb.rs b/link-for-later/src/repository/mongodb.rs index 13ee7f2..13ca5be 100644 --- a/link-for-later/src/repository/mongodb.rs +++ b/link-for-later/src/repository/mongodb.rs @@ -2,11 +2,12 @@ use std::str::FromStr; use axum::async_trait; use bson::{doc, Bson}; +use futures::TryStreamExt; use mongodb::{options::ReplaceOptions, Collection, Database}; use crate::types::{links::LinkItem, repository::Links, AppError, Result}; -const LINKS_COLLECTION_NAME: &str = "v0/links"; +const LINKS_COLLECTION_NAME: &str = "v1/links"; pub struct MongoDbRepository { collection: Collection, @@ -21,6 +22,16 @@ impl MongoDbRepository { #[async_trait] impl Links for MongoDbRepository { + async fn list(&self) -> Result> { + match self.collection.find(None, None).await { + Ok(result) => Ok(result.try_collect().await.unwrap_or_else(|_| vec![])), + Err(e) => { + tracing::error!("Error: find(): {e:?}"); + Err(AppError::DatabaseError) + } + } + } + async fn post(&self, item: &LinkItem) -> Result { match self.collection.insert_one(item, None).await { Ok(result) => { @@ -30,6 +41,12 @@ impl Links for MongoDbRepository { tracing::error!("Error: unexpected inserted_id: {}", result.inserted_id); return Err(AppError::DatabaseError); }; + let query = doc! {"_id": result.inserted_id}; + let update = doc! {"$set": doc! { "id": &id } }; + self.collection + .update_one(query, update, None) + .await + .unwrap(); let returned_item = item.clone().id(&id); Ok(returned_item) } @@ -45,8 +62,8 @@ impl Links for MongoDbRepository { tracing::error!("Error: {id} cannot be converted to Bson ObjectId"); return Err(AppError::ItemNotFound); }; - let filter = doc! {"_id": oid}; - match self.collection.find_one(filter, None).await { + let query = doc! {"_id": oid}; + match self.collection.find_one(query, None).await { Ok(item) => item.map_or(Err(AppError::ItemNotFound), |item| { let returned_item = item.id(id); Ok(returned_item) @@ -63,9 +80,9 @@ impl Links for MongoDbRepository { tracing::error!("Error: {id} cannot be converted to Bson ObjectId"); return Err(AppError::ItemNotFound); }; - let filter = doc! {"_id": id}; + let query = doc! {"_id": id}; let opts = ReplaceOptions::builder().upsert(true).build(); - match self.collection.replace_one(filter, item, Some(opts)).await { + match self.collection.replace_one(query, item, Some(opts)).await { Ok(_) => Ok(item.clone()), Err(e) => { tracing::error!("Error: replace_one(): {e:?}");