Browse Source

WIP: basic API

develop
chodak166 4 months ago
parent
commit
911a9a0256
  1. 5
      apps/app_api/src/api.rs
  2. 78
      apps/app_api/src/api/dictionary.rs
  3. 2
      apps/app_api/src/commands/listen.rs
  4. 38
      apps/app_api/src/container.rs
  5. 8
      apps/app_api/src/router.rs
  6. 16
      apps/app_api/src/state.rs
  7. 2
      lib/src/lib.rs

5
apps/app_api/src/api.rs

@ -2,8 +2,11 @@ use crate::state::AppState;
use axum::Router; use axum::Router;
use std::sync::Arc; use std::sync::Arc;
pub mod dictionary;
pub mod health; pub mod health;
pub fn routes() -> Router<Arc<AppState>> { pub fn routes() -> Router<Arc<AppState>> {
Router::new().nest("/api", health::routes()) Router::new()
.nest("/api", health::routes())
.nest("/api", dictionary::routes())
} }

78
apps/app_api/src/api/dictionary.rs

@ -0,0 +1,78 @@
use axum::{Json, Router, extract::State, http::StatusCode, response::IntoResponse, routing::get};
use serde::Serialize;
use std::sync::Arc;
use crate::state::AppState;
// --- DTOs ---
#[derive(Debug, Serialize)]
pub struct DictListResponse {
pub dictionaries: Vec<DictListEntryResponse>,
}
#[derive(Debug, Serialize)]
pub struct DictListEntryResponse {
pub name: String,
pub entry_count: u64,
}
#[derive(Debug, Serialize)]
pub struct ErrorResponse {
pub error: String,
}
impl IntoResponse for ErrorResponse {
fn into_response(self) -> axum::response::Response {
(StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response()
}
}
impl From<anyhow::Error> for ErrorResponse {
fn from(err: anyhow::Error) -> Self {
Self {
error: err.to_string(),
}
}
}
impl From<applib::RepositoryError> for ErrorResponse {
fn from(err: applib::RepositoryError) -> Self {
Self {
error: err.to_string(),
}
}
}
// --- Handlers ---
pub async fn list_dicts_handler(
State(state): State<Arc<AppState>>,
) -> Result<Json<DictListResponse>, ErrorResponse> {
let default_repo = state.container.create_dict_repo("default").await?;
let dict_names = default_repo.fetch_dicts().await?;
let mut entries = Vec::with_capacity(dict_names.len());
for dict_name in dict_names {
let dict_repo = state.container.create_dict_repo(&dict_name).await?;
let entry_count = dict_repo.count_entries().await?;
entries.push(DictListEntryResponse {
name: dict_name,
entry_count,
});
}
Ok(Json(DictListResponse {
dictionaries: entries,
}))
}
// --- Router ---
pub fn routes() -> Router<Arc<AppState>> {
Router::new().route("/dicts", get(list_dicts_handler))
}

2
apps/app_api/src/commands/listen.rs

@ -61,7 +61,7 @@ impl Executable for ListenCmd {
.as_ref() .as_ref()
.ok_or_else(|| anyhow::anyhow!("Listen config missing"))?; .ok_or_else(|| anyhow::anyhow!("Listen config missing"))?;
let app = router::create_router(); let app = router::create_router().await?;
let addr = format!("{}:{}", listen_config.host, listen_config.port); let addr = format!("{}:{}", listen_config.host, listen_config.port);
let listener = TcpListener::bind(&addr).await?; let listener = TcpListener::bind(&addr).await?;

38
apps/app_api/src/container.rs

@ -1,11 +1,11 @@
// use std::sync::Arc; use std::sync::Arc;
// use applib::DictImporter; use applib::DictImporter;
// use applib::DictRepository; use applib::DictRepository;
// use applib::SqliteDictRepository; use applib::SqliteDictRepository;
// use applib::SystemDecoder; use applib::SystemDecoder;
// use applib::SystemEncoder; use applib::SystemEncoder;
// use applib::sys_major as major; use applib::sys_major as major;
#[derive(Clone)] #[derive(Clone)]
pub struct Container; pub struct Container;
@ -15,17 +15,17 @@ impl Container {
Ok(Self) Ok(Self)
} }
// pub async fn create_dict_importer(&self, dict_name: &str) -> anyhow::Result<DictImporter> { pub async fn create_dict_importer(&self, dict_name: &str) -> anyhow::Result<DictImporter> {
// let repo = self.create_dict_repo(dict_name).await?; let repo = self.create_dict_repo(dict_name).await?;
// Ok(DictImporter::new(repo)) Ok(DictImporter::new(repo))
// } }
// pub async fn create_dict_repo( pub async fn create_dict_repo(
// &self, &self,
// dict_name: &str, dict_name: &str,
// ) -> anyhow::Result<Arc<dyn DictRepository>> { ) -> anyhow::Result<Arc<dyn DictRepository>> {
// let mut dict_repo = SqliteDictRepository::new("sqlite:app.db").await?; let mut dict_repo = SqliteDictRepository::new("sqlite:app.db").await?;
// dict_repo.use_dict(dict_name); dict_repo.use_dict(dict_name);
// Ok(Arc::new(dict_repo)) Ok(Arc::new(dict_repo))
// } }
} }

8
apps/app_api/src/router.rs

@ -5,11 +5,11 @@ use tower_http::{cors::CorsLayer, trace::TraceLayer};
use crate::api; use crate::api;
use crate::state::AppState; use crate::state::AppState;
pub fn create_router() -> Router { pub async fn create_router() -> anyhow::Result<Router> {
let state = Arc::new(AppState::new()); let state = Arc::new(AppState::new().await?);
api::routes() Ok(api::routes()
.with_state(state) .with_state(state)
.layer(TraceLayer::new_for_http()) .layer(TraceLayer::new_for_http())
.layer(CorsLayer::permissive()) .layer(CorsLayer::permissive()))
} }

16
apps/app_api/src/state.rs

@ -1,23 +1,21 @@
pub const APP_NAME: &str = env!("CARGO_PKG_NAME"); pub const APP_NAME: &str = env!("CARGO_PKG_NAME");
pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
use crate::container::Container;
#[derive(Clone)] #[derive(Clone)]
pub struct AppState { pub struct AppState {
pub name: String, pub name: String,
pub version: String, pub version: String,
pub container: Container,
} }
impl AppState { impl AppState {
pub fn new() -> Self { pub async fn new() -> anyhow::Result<Self> {
Self { Ok(Self {
name: APP_NAME.to_string(), name: APP_NAME.to_string(),
version: APP_VERSION.to_string(), version: APP_VERSION.to_string(),
} container: Container::new().await?,
} })
}
impl Default for AppState {
fn default() -> Self {
Self::new()
} }
} }

2
lib/src/lib.rs

@ -14,6 +14,8 @@ pub mod sys_major;
pub use self::common::SystemDecoder; pub use self::common::SystemDecoder;
pub use self::common::SystemEncoder; pub use self::common::SystemEncoder;
pub use self::common::errors::RepositoryError;
pub use self::dictionary::DictImporter; pub use self::dictionary::DictImporter;
pub use self::dictionary::DictRepository; pub use self::dictionary::DictRepository;
pub use self::dictionary::JsonFileDictSource; pub use self::dictionary::JsonFileDictSource;

Loading…
Cancel
Save