feat(api): wire POST /tabs/parse endpoint with fetcher and parser
This commit is contained in:
1
crates/api/src/routes/mod.rs
Normal file
1
crates/api/src/routes/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod tabs;
|
||||
41
crates/api/src/routes/tabs.rs
Normal file
41
crates/api/src/routes/tabs.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use domain::{TabFetcherPort, TabParserPort, TabSource};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
pub struct AppState {
|
||||
pub fetcher: Box<dyn TabFetcherPort>,
|
||||
pub parser: Box<dyn TabParserPort>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ParseRequest {
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ErrorResponse {
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
pub async fn parse_tab(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Json(body): Json<ParseRequest>,
|
||||
) -> Result<Json<domain::Song>, (StatusCode, Json<ErrorResponse>)> {
|
||||
let source = if body.source.starts_with("file://") {
|
||||
let path = body.source.trim_start_matches("file://");
|
||||
TabSource::File(PathBuf::from(path))
|
||||
} else {
|
||||
TabSource::Url(body.source)
|
||||
};
|
||||
|
||||
let html = state.fetcher.fetch(source).await.map_err(|e| {
|
||||
(StatusCode::BAD_GATEWAY, Json(ErrorResponse { error: e.to_string() }))
|
||||
})?;
|
||||
|
||||
let song = state.parser.parse(&html).map_err(|e| {
|
||||
(StatusCode::UNPROCESSABLE_ENTITY, Json(ErrorResponse { error: e.to_string() }))
|
||||
})?;
|
||||
|
||||
Ok(Json(song))
|
||||
}
|
||||
Reference in New Issue
Block a user