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
#![cfg(feature = "actix-web")]

use actix_web::{
    dev::HttpServiceFactory, guard::Get, web, web::Data, HttpResponse, Resource,
    Responder as ActixResponder,
};

use utoipa::openapi::OpenApi;

use crate::{Config, SwaggerUi};

impl HttpServiceFactory for SwaggerUi {
    fn register(self, config: &mut actix_web::dev::AppService) {
        let urls = self
            .urls
            .into_iter()
            .map(|url| {
                let (url, openapi) = url;
                register_api_doc_url_resource(url.url.as_ref(), openapi, config);
                url
            })
            .collect::<Vec<_>>();

        let swagger_resource = Resource::new(self.path.as_ref())
            .guard(Get())
            .app_data(Data::new(if let Some(config) = self.config {
                config.configure_defaults(urls)
            } else {
                Config::new(urls)
            }))
            .to(serve_swagger_ui);

        HttpServiceFactory::register(swagger_resource, config);
    }
}

fn register_api_doc_url_resource(url: &str, api: OpenApi, config: &mut actix_web::dev::AppService) {
    pub async fn get_api_doc(api_doc: web::Data<OpenApi>) -> impl ActixResponder {
        HttpResponse::Ok().json(api_doc.as_ref())
    }

    let url_resource = Resource::new(url)
        .guard(Get())
        .app_data(Data::new(api))
        .to(get_api_doc);
    HttpServiceFactory::register(url_resource, config);
}

async fn serve_swagger_ui(path: web::Path<String>, data: web::Data<Config<'_>>) -> HttpResponse {
    match super::serve(&*path.into_inner(), data.into_inner()) {
        Ok(swagger_file) => swagger_file
            .map(|file| {
                HttpResponse::Ok()
                    .content_type(file.content_type)
                    .body(file.bytes.to_vec())
            })
            .unwrap_or_else(|| HttpResponse::NotFound().finish()),
        Err(error) => HttpResponse::InternalServerError().body(error.to_string()),
    }
}