1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
mod handlers;

use rocket::http::{ContentType};
use rocket::{Route};
use crate::handlers::{ContentHandler, RedirectHandler};
use swagger_ui::{Assets, Config, Spec};
use std::path::Path;

fn mime_type(filename: &str) -> ContentType {
    let parts = filename.split('.').collect::<Vec<&str>>();
    match parts.last() {
        Some(v) =>
            match *v {
                "html" => ContentType::HTML,
                "js" => ContentType::JavaScript,
                "png" => ContentType::PNG,
                "css" => ContentType::CSS,
                _ => ContentType::Plain
            },
        _ => ContentType::Plain
    }
}

pub fn routes(spec: Spec, mut config: Config) -> Vec<Route> {
    let spec_handler =
        ContentHandler::bytes(
            mime_type(spec.name.as_str()),
            Vec::from(spec.content),
        );

    let spec_name: &str =
        Path::new(&spec.name)
            .file_name()
            .unwrap_or("openapi.json".as_ref())
            .to_str()
            .unwrap_or("openapi.json".as_ref());

    config.url = String::from(spec_name);

    let config_handler = ContentHandler::json(&config);

    let mut routes = vec![
        config_handler.into_route(format!("/{}", "swagger-ui-config.json")),
        spec_handler.into_route(format!("/{}", spec_name)),
        RedirectHandler::to("index.html").into_route("/"),
    ];

    for file in Assets::iter() {
        let filename = file.as_ref();
        let mime_type = mime_type(filename);

        let content: Vec<u8> = Assets::get(filename).unwrap().into_owned();

        let path = format!("/{}", filename);
        let handler = ContentHandler::bytes(mime_type, content);
        let route = handler.into_route(path);

        routes.push(route);
    };

    routes
}

#[cfg(test)]
mod tests {
    use rocket;
    use rocket::local::Client;
    use rocket::http::Status;

    fn ignite() -> rocket::Rocket {
        rocket::ignite()
            .mount("/api/v1/swagger/",
                   super::routes(
                       // Specify file with openapi specification,
                       // relative to current file
                       swagger_ui::swagger_spec_file!("../../swagger-ui/examples/openapi.json"),
                       swagger_ui::Config { ..Default::default() },
                   ),
            )
    }

    #[test]
    fn swagger_ui() {
        let client = Client::new(ignite()).expect("valid rocket instance");

        let response = client.get("/api/v1/swagger").dispatch();
        assert_eq!(response.status(), Status::SeeOther);

        let response = client.get("/api/v1/swagger/index.html").dispatch();
        assert_eq!(response.status(), Status::Ok);

        let response = client.get("/api/v1/swagger/swagger-ui-config.json").dispatch();
        assert_eq!(response.status(), Status::Ok);

        let mut response = client.get("/api/v1/swagger/openapi.json").dispatch();
        assert_eq!(response.status(), Status::Ok);

        let path = env!("CARGO_MANIFEST_DIR").to_string() + "/../swagger-ui/examples/openapi.json";

        println!("Loading {}", path);

        assert_eq!(
            response.body_string().unwrap(),
            String::from_utf8(std::fs::read(path).unwrap()).unwrap()
        );
    }
}