add output formatter
This commit is contained in:
		@ -23,6 +23,7 @@ pub mod api {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub mod server {
 | 
					pub mod server {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub mod formatter;
 | 
				
			||||||
    pub mod rest;
 | 
					    pub mod rest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										51
									
								
								src/server/formatter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/server/formatter.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					use failure::*;
 | 
				
			||||||
 | 
					use serde_json::{json, Value};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct OutputFormatter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub format_result: fn(data: &Value) -> (Vec<u8>, &'static str),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn json_format_result(data: &Value) -> (Vec<u8>, &'static str) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let content_type = "application/json;charset=UTF-8";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let result = json!({
 | 
				
			||||||
 | 
					        "data": data
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // todo: set result.total result.changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let json_str = result.to_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let raw = json_str.into_bytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (raw, content_type)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub static JSON_FORMATTER: OutputFormatter = OutputFormatter {
 | 
				
			||||||
 | 
					    format_result: json_format_result,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn extjs_format_result(data: &Value) -> (Vec<u8>, &'static str) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let content_type = "application/json;charset=UTF-8";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let result = json!({
 | 
				
			||||||
 | 
					        "data": data,
 | 
				
			||||||
 | 
					        "success": true
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // todo: set result.total result.changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let json_str = result.to_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let raw = json_str.into_bytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (raw, content_type)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub static EXTJS_FORMATTER: OutputFormatter = OutputFormatter {
 | 
				
			||||||
 | 
					    format_result: extjs_format_result,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
use crate::api::schema::*;
 | 
					use crate::api::schema::*;
 | 
				
			||||||
use crate::api::router::*;
 | 
					use crate::api::router::*;
 | 
				
			||||||
use crate::api::config::*;
 | 
					use crate::api::config::*;
 | 
				
			||||||
 | 
					use super::formatter::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
use std::path::{Path, PathBuf};
 | 
					use std::path::{Path, PathBuf};
 | 
				
			||||||
@ -66,7 +67,7 @@ impl Service for ApiService {
 | 
				
			|||||||
            match result {
 | 
					            match result {
 | 
				
			||||||
                Ok(res) => Ok::<_, hyper::Error>(res),
 | 
					                Ok(res) => Ok::<_, hyper::Error>(res),
 | 
				
			||||||
                Err(err) => {
 | 
					                Err(err) => {
 | 
				
			||||||
                    if let Some(apierr) = err.downcast_ref::<HttpError>() {
 | 
					                     if let Some(apierr) = err.downcast_ref::<HttpError>() {
 | 
				
			||||||
                        let mut resp = Response::new(Body::from(apierr.message.clone()));
 | 
					                        let mut resp = Response::new(Body::from(apierr.message.clone()));
 | 
				
			||||||
                        *resp.status_mut() = apierr.code;
 | 
					                        *resp.status_mut() = apierr.code;
 | 
				
			||||||
                        Ok(resp)
 | 
					                        Ok(resp)
 | 
				
			||||||
@ -140,6 +141,7 @@ fn get_request_parameters_async(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if let Some(query_str) = parts.uri.query() {
 | 
					            if let Some(query_str) = parts.uri.query() {
 | 
				
			||||||
                for (k, v) in form_urlencoded::parse(query_str.as_bytes()).into_owned() {
 | 
					                for (k, v) in form_urlencoded::parse(query_str.as_bytes()).into_owned() {
 | 
				
			||||||
 | 
					                    if k == "_dc" { continue; } // skip extjs "disable cache" parameter
 | 
				
			||||||
                    param_list.push((k, v));
 | 
					                    param_list.push((k, v));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -159,6 +161,7 @@ fn get_request_parameters_async(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn handle_sync_api_request(
 | 
					fn handle_sync_api_request(
 | 
				
			||||||
    info: &'static ApiMethod,
 | 
					    info: &'static ApiMethod,
 | 
				
			||||||
 | 
					    formatter: &'static OutputFormatter,
 | 
				
			||||||
    parts: Parts,
 | 
					    parts: Parts,
 | 
				
			||||||
    req_body: Body,
 | 
					    req_body: Body,
 | 
				
			||||||
    uri_param: HashMap<String, String>,
 | 
					    uri_param: HashMap<String, String>,
 | 
				
			||||||
@ -185,15 +188,16 @@ fn handle_sync_api_request(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            Ok(res)
 | 
					            Ok(res)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }).then(|result| {
 | 
					        }).then(move |result| {
 | 
				
			||||||
            match result {
 | 
					            match result {
 | 
				
			||||||
                Ok(ref value) => {
 | 
					                Ok(ref value) => {
 | 
				
			||||||
                    let json_str = value.to_string();
 | 
					
 | 
				
			||||||
 | 
					                    let (raw, content_type) = (formatter.format_result)(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    Ok(Response::builder()
 | 
					                    Ok(Response::builder()
 | 
				
			||||||
                       .status(StatusCode::OK)
 | 
					                       .status(StatusCode::OK)
 | 
				
			||||||
                       .header(header::CONTENT_TYPE, "application/json")
 | 
					                       .header(header::CONTENT_TYPE, content_type)
 | 
				
			||||||
                       .body(Body::from(json_str))?)
 | 
					                       .body(Body::from(raw))?)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Err(err) => Err(http_err!(BAD_REQUEST, err.to_string()))
 | 
					                Err(err) => Err(http_err!(BAD_REQUEST, err.to_string()))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -374,15 +378,19 @@ pub fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> BoxFut {
 | 
				
			|||||||
        println!("GOT API REQUEST");
 | 
					        println!("GOT API REQUEST");
 | 
				
			||||||
        if comp_len >= 2 {
 | 
					        if comp_len >= 2 {
 | 
				
			||||||
            let format = components[1];
 | 
					            let format = components[1];
 | 
				
			||||||
            if format != "json" {
 | 
					            let formatter = match format {
 | 
				
			||||||
                return Box::new(future::err(http_err!(BAD_REQUEST, format!("Unsupported output format '{}'.", format))))
 | 
					                "json" => &JSON_FORMATTER,
 | 
				
			||||||
            }
 | 
					                "extjs" => &EXTJS_FORMATTER,
 | 
				
			||||||
 | 
					                _ =>  {
 | 
				
			||||||
 | 
					                    return Box::new(future::err(http_err!(BAD_REQUEST, format!("Unsupported output format '{}'.", format))));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let mut uri_param = HashMap::new();
 | 
					            let mut uri_param = HashMap::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if let Some(api_method) = api.find_method(&components[2..], method, &mut uri_param) {
 | 
					            if let Some(api_method) = api.find_method(&components[2..], method, &mut uri_param) {
 | 
				
			||||||
                // fixme: handle auth
 | 
					                // fixme: handle auth
 | 
				
			||||||
                return handle_sync_api_request(api_method, parts, body, uri_param);
 | 
					                return handle_sync_api_request(api_method, formatter, parts, body, uri_param);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user