df_st_api 0.3.0-development-2

Starting an API server for the DF Storyteller project.
use anyhow::Error;
use df_rocket_okapi::{
    gen::OpenApiGenerator, request::get_nested_query_parameters, request::OpenApiFromQuery,
};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use rocket::request::{FromQuery, Query};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;

/// A Query Guard for pagination of lists of items.
#[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema)]
pub struct ApiCountPagination {
    /// Number of the page you want to request. (starting from page 0)
    pub page: Option<u32>,
    /// Number of maximum items per page. (at least 1)
    pub per_page: Option<u32>,
    /// Tag to identify the version of the page requested.
    /// [More info here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag).
    pub etag: Option<String>,
    /// Allows filtering over a property.
    /// The property has to be of type `String` or `i32`, so it will not work for all properties.
    /// Example: "type" or "year".
    pub filter_by: Option<String>,
    /// The values that is used as the filter. Example: "hf_died" or "1000".
    /// If value is wrong type a `400 Bad Request` will be returned.
    pub filter_value: Option<String>,
}

/// Parse incoming query data and store in `ApiCountPagination`
impl<'q> FromQuery<'q> for ApiCountPagination {
    type Error = Error; //TODO Custom error

    fn from_query(query: Query<'q>) -> Result<Self, Self::Error> {
        let mut api_page_request = ApiCountPagination::default();
        for key in query {
            match key.key.url_decode()?.as_ref() {
                "page" => api_page_request.page = Some(key.value.parse::<u32>()?),
                "per_page" => api_page_request.per_page = Some(key.value.parse::<u32>()?),
                "etag" => api_page_request.etag = Some(key.value.url_decode_lossy()),
                "filter_by" => api_page_request.filter_by = Some(key.value.url_decode_lossy()),
                "filter_value" => {
                    api_page_request.filter_value = Some(key.value.url_decode_lossy())
                }
                _ => {}
            }
        }
        Ok(api_page_request)
    }
}

/// Add support for OpenApi generator
impl<'r> OpenApiFromQuery<'r> for ApiCountPagination {
    fn query_multi_parameter(
        gen: &mut OpenApiGenerator,
        name: String,
        required: bool,
    ) -> df_rocket_okapi::Result<Vec<okapi::openapi3::Parameter>> {
        Ok(get_nested_query_parameters::<ApiCountPagination>(
            gen, name, required,
        ))
    }
}