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 std::sync::Arc;
pub mod dictionary;
pub mod health;
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()
.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 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::DictRepository;
// use applib::SqliteDictRepository;
// use applib::SystemDecoder;
// use applib::SystemEncoder;
// use applib::sys_major as major;
use applib::DictImporter;
use applib::DictRepository;
use applib::SqliteDictRepository;
use applib::SystemDecoder;
use applib::SystemEncoder;
use applib::sys_major as major;
#[derive(Clone)]
pub struct Container;
@ -15,17 +15,17 @@ impl Container {
Ok(Self)
}
// pub async fn create_dict_importer(&self, dict_name: &str) -> anyhow::Result<DictImporter> {
// let repo = self.create_dict_repo(dict_name).await?;
// Ok(DictImporter::new(repo))
// }
pub async fn create_dict_importer(&self, dict_name: &str) -> anyhow::Result<DictImporter> {
let repo = self.create_dict_repo(dict_name).await?;
Ok(DictImporter::new(repo))
}
// pub async fn create_dict_repo(
// &self,
// dict_name: &str,
// ) -> anyhow::Result<Arc<dyn DictRepository>> {
// let mut dict_repo = SqliteDictRepository::new("sqlite:app.db").await?;
// dict_repo.use_dict(dict_name);
// Ok(Arc::new(dict_repo))
// }
pub async fn create_dict_repo(
&self,
dict_name: &str,
) -> anyhow::Result<Arc<dyn DictRepository>> {
let mut dict_repo = SqliteDictRepository::new("sqlite:app.db").await?;
dict_repo.use_dict(dict_name);
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::state::AppState;
pub fn create_router() -> Router {
let state = Arc::new(AppState::new());
pub async fn create_router() -> anyhow::Result<Router> {
let state = Arc::new(AppState::new().await?);
api::routes()
Ok(api::routes()
.with_state(state)
.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_VERSION: &str = env!("CARGO_PKG_VERSION");
use crate::container::Container;
#[derive(Clone)]
pub struct AppState {
pub name: String,
pub version: String,
pub container: Container,
}
impl AppState {
pub fn new() -> Self {
Self {
pub async fn new() -> anyhow::Result<Self> {
Ok(Self {
name: APP_NAME.to_string(),
version: APP_VERSION.to_string(),
}
}
}
impl Default for AppState {
fn default() -> Self {
Self::new()
container: Container::new().await?,
})
}
}

2
lib/src/lib.rs

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

Loading…
Cancel
Save