I want to create a actix-web server where I can provide my Search
trait as application data in order to easily swap between multiple implementations or use mock implementation for testing. Whatever I try I can't get it to compile or when I get it to compile I get the following error when visiting the route in the web browser:
App data is not configured, to configure use App::data()
Here is what I have so far
# Cargo.toml
[dependencies]
actix-rt = "1.1.1"
actix-web = "3.3.2"
[dev-dependencies]
tokio = "0.2.22"
//! main.rs
use actix_web::dev::Server;
use actix_web::{get, web, App, HttpServer, Responder};
pub trait Search {
fn search(&self, query: &str) -> String;
}
#[derive(Clone)]
pub struct SearchClient {
base_url: String,
}
impl SearchClient {
pub fn new() -> Self {
Self {
base_url: String::from("/search"),
}
}
}
impl Search for SearchClient {
fn search(&self, query: &str) -> String {
format!("Searching in SearchClient: {}", query)
}
}
#[get("/{query}")]
async fn index(
web::Path(query): web::Path<String>,
search: web::Data<dyn Search>,
) -> impl Responder {
search.into_inner().search(&query)
}
pub fn create_server(
search: impl Search + Send + Sync + 'static + Clone,
) -> Result<Server, std::io::Error> {
let server = HttpServer::new(move || App::new().data(search.clone()).service(index))
.bind("127.0.0.1:8080")?
.run();
Ok(server)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let search_client = SearchClient::new();
create_server(search_client).unwrap().await
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone)]
pub struct TestClient;
impl Search for TestClient {
fn search(&self, query: &str) -> String {
format!("Searching in TestClient: {}", query)
}
}
#[actix_rt::test]
async fn test_search() {
let search_client = TestClient {};
let server = create_server(search_client).unwrap();
tokio::spawn(server);
}
}