chore: add svg endpoints to cellar API cd767ec6
Steve · 2026-04-24 21:56 2 file(s) · +66 −0
apps/cellar/src/server/handlers/public.rs +64 −0
108 108
    }
109 109
}
110 110
111 +
pub async fn api_get_pentagon_svg(
112 +
    State(state): State<Arc<AppState>>,
113 +
    Path(short_id): Path<String>,
114 +
) -> Response {
115 +
    match db::get_wine_by_short_id(&state.db, &short_id) {
116 +
        Ok(Some(wine)) => {
117 +
            let svg = build_pentagon_svg(
118 +
                wine.sweetness,
119 +
                wine.acidity,
120 +
                wine.tannin,
121 +
                wine.alcohol,
122 +
                wine.body,
123 +
                250.0,
124 +
                true,
125 +
            );
126 +
            (
127 +
                StatusCode::OK,
128 +
                [(
129 +
                    axum::http::header::CONTENT_TYPE,
130 +
                    HeaderValue::from_static("image/svg+xml"),
131 +
                )],
132 +
                svg,
133 +
            )
134 +
                .into_response()
135 +
        }
136 +
        Ok(None) => StatusCode::NOT_FOUND.into_response(),
137 +
        Err(e) => {
138 +
            tracing::error!("api_get_pentagon_svg: {}", e);
139 +
            StatusCode::INTERNAL_SERVER_ERROR.into_response()
140 +
        }
141 +
    }
142 +
}
143 +
144 +
pub async fn api_get_bars_svg(
145 +
    State(state): State<Arc<AppState>>,
146 +
    Path(short_id): Path<String>,
147 +
) -> Response {
148 +
    match db::get_wine_by_short_id(&state.db, &short_id) {
149 +
        Ok(Some(wine)) => {
150 +
            let svg = build_bars_svg(
151 +
                wine.clarity,
152 +
                wine.color_intensity,
153 +
                wine.aroma_intensity,
154 +
                wine.nose_complexity,
155 +
                250.0,
156 +
            );
157 +
            (
158 +
                StatusCode::OK,
159 +
                [(
160 +
                    axum::http::header::CONTENT_TYPE,
161 +
                    HeaderValue::from_static("image/svg+xml"),
162 +
                )],
163 +
                svg,
164 +
            )
165 +
                .into_response()
166 +
        }
167 +
        Ok(None) => StatusCode::NOT_FOUND.into_response(),
168 +
        Err(e) => {
169 +
            tracing::error!("api_get_bars_svg: {}", e);
170 +
            StatusCode::INTERNAL_SERVER_ERROR.into_response()
171 +
        }
172 +
    }
173 +
}
174 +
111 175
pub async fn get_wine_image(
112 176
    State(state): State<Arc<AppState>>,
113 177
    Path(short_id): Path<String>,
apps/cellar/src/server/mod.rs +2 −0
542 542
    let api = Router::new()
543 543
        .route("/api/wines", get(public::api_list_wines))
544 544
        .route("/api/wines/{short_id}", get(public::api_get_wine))
545 +
        .route("/api/wines/{short_id}/pentagon.svg", get(public::api_get_pentagon_svg))
546 +
        .route("/api/wines/{short_id}/bars.svg", get(public::api_get_bars_svg))
545 547
        .layer(cors);
546 548
547 549
    let app = Router::new()