Add ResponseBuilder to rest_api

This commit is contained in:
Paul Hauner 2019-09-02 14:29:36 +10:00
parent d05c2d4110
commit 6c50758bdf
No known key found for this signature in database
GPG Key ID: 5E2CFF9B75FA63DF
4 changed files with 61 additions and 13 deletions

View File

@ -14,9 +14,12 @@ store = { path = "../store" }
version = { path = "../version" } version = { path = "../version" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "^1.0" serde_json = "^1.0"
serde_yaml = "0.8"
slog = "^2.2.3" slog = "^2.2.3"
slog-term = "^2.4.0" slog-term = "^2.4.0"
slog-async = "^2.3.0" slog-async = "^2.3.0"
eth2_ssz = { path = "../../eth2/utils/ssz" }
eth2_ssz_derive = { path = "../../eth2/utils/ssz_derive" }
state_processing = { path = "../../eth2/state_processing" } state_processing = { path = "../../eth2/state_processing" }
types = { path = "../../eth2/types" } types = { path = "../../eth2/types" }
clap = "2.32.0" clap = "2.32.0"

View File

@ -1,8 +1,9 @@
use super::{success_response, ApiResult}; use super::{success_response, ApiResult, ResponseBuilder};
use crate::{helpers::*, ApiError, UrlQuery}; use crate::{helpers::*, ApiError, UrlQuery};
use beacon_chain::{BeaconChain, BeaconChainTypes}; use beacon_chain::{BeaconChain, BeaconChainTypes};
use hyper::{Body, Request}; use hyper::{Body, Request};
use serde::Serialize; use serde::Serialize;
use ssz_derive::Encode;
use std::sync::Arc; use std::sync::Arc;
use store::Store; use store::Store;
use types::{BeaconBlock, BeaconState, EthSpec, Hash256, Slot}; use types::{BeaconBlock, BeaconState, EthSpec, Hash256, Slot};
@ -33,7 +34,7 @@ pub fn get_head<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
Ok(success_response(Body::from(json))) Ok(success_response(Body::from(json)))
} }
#[derive(Serialize)] #[derive(Serialize, Encode)]
#[serde(bound = "T: EthSpec")] #[serde(bound = "T: EthSpec")]
pub struct BlockResponse<T: EthSpec> { pub struct BlockResponse<T: EthSpec> {
pub root: Hash256, pub root: Hash256,
@ -77,11 +78,7 @@ pub fn get_block<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
beacon_block: block, beacon_block: block,
}; };
let json: String = serde_json::to_string(&response).map_err(|e| { ResponseBuilder::new(&req).body(&response)
ApiError::ServerError(format!("Unable to serialize BlockResponse: {:?}", e))
})?;
Ok(success_response(Body::from(json)))
} }
/// HTTP handler to return a `BeaconBlock` root at a given `slot`. /// HTTP handler to return a `BeaconBlock` root at a given `slot`.
@ -104,7 +101,7 @@ pub fn get_block_root<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiR
Ok(success_response(Body::from(json))) Ok(success_response(Body::from(json)))
} }
#[derive(Serialize)] #[derive(Serialize, Encode)]
#[serde(bound = "T: EthSpec")] #[serde(bound = "T: EthSpec")]
pub struct StateResponse<T: EthSpec> { pub struct StateResponse<T: EthSpec> {
pub root: Hash256, pub root: Hash256,
@ -144,11 +141,7 @@ pub fn get_state<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
beacon_state: state, beacon_state: state,
}; };
let json: String = serde_json::to_string(&response).map_err(|e| { ResponseBuilder::new(&req).body(&response)
ApiError::ServerError(format!("Unable to serialize StateResponse: {:?}", e))
})?;
Ok(success_response(Body::from(json)))
} }
/// HTTP handler to return a `BeaconState` root at a given `slot`. /// HTTP handler to return a `BeaconState` root at a given `slot`.

View File

@ -8,6 +8,7 @@ mod helpers;
mod metrics; mod metrics;
mod network; mod network;
mod node; mod node;
mod response_builder;
mod spec; mod spec;
mod url_query; mod url_query;
mod validator; mod validator;
@ -18,6 +19,7 @@ use eth2_config::Eth2Config;
use hyper::rt::Future; use hyper::rt::Future;
use hyper::service::service_fn_ok; use hyper::service::service_fn_ok;
use hyper::{Body, Method, Response, Server, StatusCode}; use hyper::{Body, Method, Response, Server, StatusCode};
use response_builder::ResponseBuilder;
use slog::{info, o, warn}; use slog::{info, o, warn};
use std::ops::Deref; use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;

View File

@ -0,0 +1,50 @@
use super::{ApiError, ApiResult};
use http::header;
use hyper::{Body, Request, Response, StatusCode};
use serde::Serialize;
use ssz::Encode;
pub enum Encoding {
JSON,
SSZ,
YAML,
}
pub struct ResponseBuilder {
encoding: Encoding,
}
impl ResponseBuilder {
pub fn new(req: &Request<Body>) -> Self {
let encoding = match req.headers().get(header::CONTENT_TYPE) {
Some(h) if h == "application/ssz" => Encoding::SSZ,
Some(h) if h == "application/yaml" => Encoding::YAML,
_ => Encoding::JSON,
};
Self { encoding }
}
pub fn body<T: Serialize + Encode>(self, item: &T) -> ApiResult {
let body: Body = match self.encoding {
Encoding::JSON => Body::from(serde_json::to_string(&item).map_err(|e| {
ApiError::ServerError(format!(
"Unable to serialize response body as JSON: {:?}",
e
))
})?),
Encoding::SSZ => Body::from(item.as_ssz_bytes()),
Encoding::YAML => Body::from(serde_yaml::to_string(&item).map_err(|e| {
ApiError::ServerError(format!(
"Unable to serialize response body as YAML: {:?}",
e
))
})?),
};
Response::builder()
.status(StatusCode::OK)
.body(Body::from(body))
.map_err(|e| ApiError::ServerError(format!("Failed to build response: {:?}", e)))
}
}