From 7653cc925351ae05af2fd2ca50bfbb7100f4b1ef Mon Sep 17 00:00:00 2001 From: Maki-Grz Date: Sat, 20 Dec 2025 16:50:27 +0100 Subject: [PATCH] feat(examples): add integration examples for Actix, Axum, and Rocket Add three new examples demonstrating how to use the Qdrant client within popular Rust web frameworks. Each example shows how to manage shared state and handle gRPC-to-JSON serialization. - Added actix-web, axum, and rocket to dev-dependencies - Declared examples with 'serde' required-feature in Cargo.toml - Implemented state sharing and basic endpoints in each framework --- Cargo.toml | 16 +++++++++++++ examples/actix_web.rs | 53 +++++++++++++++++++++++++++++++++++++++++++ examples/axum.rs | 39 +++++++++++++++++++++++++++++++ examples/rocket.rs | 32 ++++++++++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 examples/actix_web.rs create mode 100644 examples/axum.rs create mode 100644 examples/rocket.rs diff --git a/Cargo.toml b/Cargo.toml index 9edcb13f..7fad9a45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,10 @@ parking_lot = "0.12.4" [dev-dependencies] tonic-build = { version = "0.12.3", features = ["prost"] } +actix-web = "4.12.1" +axum = "0.8.7" +rocket = { version = "0.5.1", features = ["json"] } +serde_json = "1.0.128" [features] default = ["download_snapshots", "serde", "generate-snippets"] @@ -47,6 +51,18 @@ required-features = ["serde"] name = "deprecated_search" required-features = ["serde"] +[[example]] +name = "actix_web" +required-features = ["serde"] + +[[example]] +name = "axum" +required-features = ["serde"] + +[[example]] +name = "rocket" +required-features = ["serde"] + [package.metadata.docs.rs] features = ["download_snapshots", "serde"] no-default-features = true diff --git a/examples/actix_web.rs b/examples/actix_web.rs new file mode 100644 index 00000000..f73d1c77 --- /dev/null +++ b/examples/actix_web.rs @@ -0,0 +1,53 @@ +use std::sync::Arc; + +use actix_web::{web, App, HttpResponse, HttpServer, Responder}; +use qdrant_client::Qdrant; +use serde_json::json; + +struct AppState { + client: Arc, +} + +async fn list_collections(data: web::Data) -> impl Responder { + match data.client.list_collections().await { + Ok(collections) => { + let names: Vec = collections + .collections + .into_iter() + .map(|c| c.name) + .collect(); + HttpResponse::Ok().json(json!({ "collections": names })) + } + Err(e) => HttpResponse::InternalServerError().body(e.to_string()), + } +} + +async fn health_check(data: web::Data) -> impl Responder { + match data.client.health_check().await { + Ok(resp) => HttpResponse::Ok().json(json!({ "result": format!("{:?}", resp) })), + Err(e) => HttpResponse::InternalServerError().body(e.to_string()), + } +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + let client = Qdrant::from_url("http://localhost:6334") + .build() + .expect("Failed to create Qdrant client"); + + let state = web::Data::new(AppState { + client: Arc::new(client), + }); + + println!("Starting Actix server on http://localhost:8080"); + + HttpServer::new(move || { + App::new() + .app_data(state.clone()) + .route("/collections", web::get().to(list_collections)) + .route("/health", web::get().to(health_check)) + }) + .bind(("127.0.0.1", 8080))? + .run() + .await +} diff --git a/examples/axum.rs b/examples/axum.rs new file mode 100644 index 00000000..79adee79 --- /dev/null +++ b/examples/axum.rs @@ -0,0 +1,39 @@ +use std::sync::Arc; + +use axum::routing::get; +use axum::{Json, Router}; +use qdrant_client::Qdrant; +use serde_json::{json, Value}; + +async fn list_collections( + axum::extract::State(client): axum::extract::State>, +) -> Json { + match client.list_collections().await { + Ok(collections) => { + let names: Vec = collections + .collections + .into_iter() + .map(|c| c.name) + .collect(); + Json(json!({ "collections": names })) + } + Err(e) => Json(json!({"error": e.to_string()})), + } +} + +#[tokio::main] +async fn main() { + let client = Qdrant::from_url("http://localhost:6334") + .build() + .expect("Failed to create Qdrant client"); + + let app = Router::new() + .route("/collections", get(list_collections)) + .with_state(Arc::new(client)); + + let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") + .await + .unwrap(); + println!("Starting Axum server on http://localhost:3000"); + axum::serve(listener, app).await.unwrap(); +} diff --git a/examples/rocket.rs b/examples/rocket.rs new file mode 100644 index 00000000..ce1dd540 --- /dev/null +++ b/examples/rocket.rs @@ -0,0 +1,32 @@ +#[macro_use] +extern crate rocket; +use qdrant_client::Qdrant; +use rocket::serde::json::Json; +use rocket::State; +use serde_json::{json, Value}; + +#[get("/collections")] +async fn list_collections(client: &State) -> Json { + match client.list_collections().await { + Ok(collections) => { + let names: Vec = collections + .collections + .into_iter() + .map(|c| c.name) + .collect(); + Json(json!({ "collections": names })) + } + Err(e) => Json(json!({"error": e.to_string()})), + } +} + +#[launch] +async fn rocket() -> _ { + let client = Qdrant::from_url("http://localhost:6334") + .build() + .expect("Failed to create Qdrant client"); + + rocket::build() + .manage(client) + .mount("/", routes![list_collections]) +}