Skip to content

Commit

Permalink
[API] Rework response and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
banool committed Jul 22, 2022
1 parent 9961ce6 commit d9a170e
Show file tree
Hide file tree
Showing 13 changed files with 546 additions and 391 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ hex = "0.4.3"
hyper = "0.14.18"
mime = "0.3.16"
once_cell = "1.10.0"
paste = "1.0.7"
percent-encoding = "2.1.0"
poem = { version = "1.3.35", features = ["anyhow", "rustls"] }
poem-openapi = { version = "2.0.5", features = ["swagger-ui", "url"] }
Expand Down
54 changes: 27 additions & 27 deletions api/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use anyhow::{anyhow, ensure, format_err, Result};
use anyhow::{anyhow, ensure, format_err, Context as AnyhowContext, Result};
use aptos_api_types::{AsConverter, BlockInfo, Error, LedgerInfo, TransactionOnChainData, U64};
use aptos_config::config::{NodeConfig, RoleType};
use aptos_crypto::HashValue;
Expand All @@ -23,7 +23,6 @@ use aptos_types::{
use aptos_vm::data_cache::{IntoMoveResolver, RemoteStorageOwned};
use futures::{channel::oneshot, SinkExt};
use move_deps::move_core_types::ident_str;
use poem_openapi::payload::Json;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, convert::Infallible, sync::Arc};
use storage_interface::{
Expand All @@ -32,7 +31,7 @@ use storage_interface::{
};
use warp::{filters::BoxedFilter, Filter, Reply};

use crate::poem_backend::{AptosError, AptosErrorCode, AptosErrorResponse, AptosInternalResult};
use crate::poem_backend::{AptosErrorCode, InternalError};

// Context holds application scope context
#[derive(Clone)]
Expand Down Expand Up @@ -64,16 +63,12 @@ impl Context {
.map(|state_view| state_view.into_move_resolver())
}

pub fn move_resolver_poem(&self) -> AptosInternalResult<RemoteStorageOwned<DbStateView>> {
self.move_resolver().map_err(|e| {
AptosErrorResponse::InternalServerError(Json(
AptosError::new(
format_err!("Failed to read latest state checkpoint from DB: {}", e)
.to_string(),
)
.error_code(AptosErrorCode::ReadFromStorageError),
))
})
pub fn move_resolver_poem<E: InternalError>(
&self,
) -> Result<RemoteStorageOwned<DbStateView>, E> {
self.move_resolver()
.context("Failed to read latest state checkpoint from DB")
.map_err(|e| E::internal(e).error_code(AptosErrorCode::ReadFromStorageError))
}

pub fn state_view_at_version(&self, version: Version) -> Result<DbStateView> {
Expand Down Expand Up @@ -118,13 +113,21 @@ impl Context {
}
}

pub fn get_latest_ledger_info_poem(&self) -> AptosInternalResult<LedgerInfo> {
self.get_latest_ledger_info().map_err(|e| {
AptosErrorResponse::InternalServerError(Json(
AptosError::new(format_err!("Failed to retrieve ledger info: {}", e).to_string())
.error_code(AptosErrorCode::ReadFromStorageError),
// TODO: Add error codes to these errors.
pub fn get_latest_ledger_info_poem<E: InternalError>(&self) -> Result<LedgerInfo, E> {
if let Some(oldest_version) = self.db.get_first_txn_version().map_err(E::internal)? {
Ok(LedgerInfo::new(
&self.chain_id(),
&self
.get_latest_ledger_info_with_signatures()
.map_err(E::internal)?,
oldest_version,
))
})
} else {
Err(E::internal(anyhow!(
"Failed to retrieve latest ledger info"
)))
}
}

pub fn get_latest_ledger_info_with_signatures(&self) -> Result<LedgerInfoWithSignatures> {
Expand All @@ -137,17 +140,14 @@ impl Context {
.get_state_value(state_key)
}

pub fn get_state_value_poem(
pub fn get_state_value_poem<E: InternalError>(
&self,
state_key: &StateKey,
version: u64,
) -> Result<Option<Vec<u8>>, AptosErrorResponse> {
self.get_state_value(state_key, version).map_err(|e| {
AptosErrorResponse::InternalServerError(Json(
AptosError::new(format_err!("Failed to retrieve state value: {}", e).to_string())
.error_code(AptosErrorCode::ReadFromStorageError),
))
})
) -> Result<Option<Vec<u8>>, E> {
self.get_state_value(state_key, version)
.context("Failed to retrieve state value")
.map_err(|e| E::internal(e).error_code(AptosErrorCode::ReadFromStorageError))
}

pub fn get_state_values(
Expand Down
9 changes: 5 additions & 4 deletions api/src/failpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use anyhow::{format_err, Result};
use aptos_api_types::Error;

use crate::poem_backend::{AptosError, AptosErrorResponse};
use crate::poem_backend::{AptosError, InternalError};
use poem_openapi::payload::Json;

#[allow(unused_variables)]
Expand All @@ -19,10 +19,11 @@ pub fn fail_point(name: &str) -> Result<(), Error> {

#[allow(unused_variables)]
#[inline]
pub fn fail_point_poem(name: &str) -> Result<(), AptosErrorResponse> {
pub fn fail_point_poem<E: InternalError>(name: &str) -> Result<(), E> {
Ok(fail::fail_point!(format!("api::{}", name).as_str(), |_| {
Err(AptosErrorResponse::InternalServerError(Json(
AptosError::new(format!("unexpected internal error for {}", name)),
Err(E::internal_str(&format!(
"unexpected internal error for {}",
name
)))
}))
}
40 changes: 18 additions & 22 deletions api/src/poem_backend/accept_type.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,34 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use std::convert::TryFrom;

use poem::web::Accept;
use poem_openapi::payload::Json;

use super::{AptosError, AptosErrorCode, AptosErrorResponse};
use super::{AptosErrorCode, BadRequestError};

#[derive(PartialEq)]
pub enum AcceptType {
Json,
Bcs,
}

impl TryFrom<&Accept> for AcceptType {
type Error = AptosErrorResponse;

fn try_from(accept: &Accept) -> Result<Self, Self::Error> {
for mime in &accept.0 {
match mime.as_ref() {
"application/json" => return Ok(AcceptType::Json),
"application/x-bcs" => return Ok(AcceptType::Bcs),
"*/*" => {}
wildcard => {
return Err(AptosErrorResponse::BadRequest(Json(
AptosError::new(format!("Invalid Accept type: {:?}", wildcard))
.error_code(AptosErrorCode::UnsupportedAcceptType),
)));
}
// I can't use TryFrom here right now:
// https://stackoverflow.com/questions/73072492/apply-trait-bounds-to-associated-type
pub fn parse_accept<E: BadRequestError>(accept: &Accept) -> Result<AcceptType, E> {
for mime in &accept.0 {
match mime.as_ref() {
"application/json" => return Ok(AcceptType::Json),
"application/x-bcs" => return Ok(AcceptType::Bcs),
"*/*" => {}
wildcard => {
return Err(E::bad_request_str(&format!(
"Unsupported Accept type: {:?}",
wildcard
))
.error_code(AptosErrorCode::UnsupportedAcceptType));
}
}

// Default to returning content as JSON.
Ok(AcceptType::Json)
}

// Default to returning content as JSON.
Ok(AcceptType::Json)
}
Loading

0 comments on commit d9a170e

Please sign in to comment.