feat: initial API and docs

This commit is contained in:
Ninjdai 2025-07-30 16:55:07 +02:00
parent 79be4eb543
commit 5d709d658b
16 changed files with 3169 additions and 342 deletions

83
src/routes/book.rs Normal file
View file

@ -0,0 +1,83 @@
use std::sync::Arc;
use axum::{extract::{Path, State}, Json};
use reqwest::{StatusCode};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use utoipa::IntoParams;
use crate::{entities::{book, prelude::{Book}}, utils::open_library};
use crate::AppState;
#[derive(IntoParams)]
#[into_params(names("id"), parameter_in = Path)]
#[allow(dead_code)]
struct BookByIdParams(u32);
#[axum::debug_handler]
#[utoipa::path(
get,
path = "/book/id/{id}",
params(BookByIdParams),
responses(
(status = OK, body = book::Model, description = "Found book with corresponding ID in the database"),
(status = NOT_FOUND, description = "No book with this id exists in the database")
),
summary = "Get a book by its internal ID",
description = "Get a book from its ID in Alexandria's internal database",
tag = "book-api",
)]
pub async fn get_book_by_id(
State(state): State<Arc<AppState>>,
Path(id): Path<u32>,
) -> (StatusCode, Json<Option<book::Model>>) {
if let Ok(Some(res)) = Book::find_by_id(id).one(state.db_conn.as_ref()).await {
(StatusCode::OK, Json(Some(res)))
} else {
(StatusCode::NOT_FOUND, Json(None))
}
}
#[derive(IntoParams)]
#[into_params(names("ean"), parameter_in = Path)]
#[allow(dead_code)]
struct BookByEanParams(String);
#[axum::debug_handler]
#[utoipa::path(
get,
path = "/book/ean/{ean}",
params(BookByEanParams),
responses(
(status = OK, body = book::Model, description = "Found book with corresponding EAN", examples(
("Found regular book" = (value = json!({"author": "Pierre Bottero", "ean": "9782700234015", "id": 5642, "title": "Ellana l'envol"}))),
("Book doesn't have an EAN" = (value = json!({"author": "Author B. Ook", "ean": "", "id": 1465312, "title": "Itsabook"})))
)),
(status = NOT_FOUND, description = "No book with this EAN found in the database or on openlibrary")
),
summary = "Get a book by its EAN",
description = "Get a book from its EAN. If it doesn't exist in its database, Alexandria will try to find it using openlibrary.org's API",
tag = "book-api"
)]
pub async fn get_book_by_ean(
State(state): State<Arc<AppState>>,
Path(ean): Path<String>,
) -> (StatusCode, Json<Option<book::Model>>) {
if let Ok(Some(res)) = Book::find().filter(book::Column::Ean.eq(&ean)).one(state.db_conn.as_ref()).await {
(StatusCode::OK, Json(Some(res)))
} else {
let fetched_book = open_library::fetch_book_by_ean(&state.web_client, &ean).await;
if let Some(book) = fetched_book {
let res = Book::insert(book.to_active_model()).exec(state.db_conn.as_ref()).await.unwrap();
(StatusCode::OK, Json(Some(book::Model {
id: res.last_insert_id,
ean: ean,
title: book.title,
author: book.author
})))
} else {
(StatusCode::NOT_FOUND, Json(None))
}
}
}