feat(api): wire POST /tabs/parse endpoint with fetcher and parser

This commit is contained in:
2026-04-08 01:56:06 +02:00
parent fe7d2dbceb
commit 0444d11fb4
4 changed files with 93 additions and 0 deletions

View File

@@ -0,0 +1 @@
pub mod tabs;

View 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))
}