Skip to content

Commit

Permalink
Simplify errors to a single error type.
Browse files Browse the repository at this point in the history
This introduces a new `ErrorResponse` type, wrapping the
`ndc_models::ErrorResponse` type and adding a status code.

Instead of each connector method returning its own error type, all
methods now return the same general type, allowing the connector
implementor to decide how best to construct it.

This supersedes the various error enums which only had an `Other` case.
Error enums with more cases have been kept (though their `Other` cases
have been removed), with `From<T> for ErrorResponse` implementations.
  • Loading branch information
SamirTalwar committed Aug 6, 2024
1 parent 4b587da commit 4de7d49
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 327 deletions.
22 changes: 7 additions & 15 deletions crates/sdk/src/check_health.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,22 @@
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum HealthCheckError {
#[error("URL parse error: {0}")]
ParseError(url::ParseError),
#[error("request error: {0}")]
RequestError(reqwest::Error),
#[error("unsuccessful response with status code: {status}\nbody:\n{body}")]
UnsuccessfulResponse {
status: reqwest::StatusCode,
body: String,
},
}

impl std::fmt::Display for HealthCheckError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HealthCheckError::ParseError(inner) => write!(f, "URL parse error: {inner}"),
HealthCheckError::RequestError(inner) => write!(f, "request error: {inner}"),
HealthCheckError::UnsuccessfulResponse { status, body } => {
write!(
f,
"unsuccessful response with status code: {status}\nbody:\n{body}"
)
}
}
impl From<HealthCheckError> for crate::connector::error::ErrorResponse {
fn from(value: HealthCheckError) -> Self {
Self::from_error(value)
}
}

impl std::error::Error for HealthCheckError {}

pub async fn check_health(host: Option<String>, port: u16) -> Result<(), HealthCheckError> {
let url = (|| -> Result<url::Url, url::ParseError> {
let mut url = reqwest::Url::parse("http://localhost/").unwrap(); // cannot fail
Expand Down
51 changes: 30 additions & 21 deletions crates/sdk/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,13 @@ pub trait Connector {
/// query metrics which cannot be updated directly, e.g.
/// the number of idle connections in a connection pool
/// can be polled but not updated directly.
fn fetch_metrics(
configuration: &Self::Configuration,
state: &Self::State,
) -> Result<(), FetchMetricsError>;
fn fetch_metrics(configuration: &Self::Configuration, state: &Self::State) -> Result<()>;

/// Check the health of the connector.
///
/// For example, this function should check that the connector
/// is able to reach its data source over the network.
async fn health_check(
configuration: &Self::Configuration,
state: &Self::State,
) -> Result<(), HealthError>;
async fn health_check(configuration: &Self::Configuration, state: &Self::State) -> Result<()>;

/// Get the connector's capabilities.
///
Expand All @@ -77,47 +71,59 @@ pub trait Connector {
/// from the NDC specification.
async fn get_schema(
configuration: &Self::Configuration,
) -> Result<JsonResponse<models::SchemaResponse>, SchemaError>;
) -> Result<JsonResponse<models::SchemaResponse>>;

/// Explain a query by creating an execution plan
///
/// This function implements the [query/explain endpoint](https://hasura.github.io/ndc-spec/specification/explain.html)
/// from the NDC specification.
///
/// The [`ExplainError`] type is provided as a convenience to connector authors, to be used on
/// error.
async fn query_explain(
configuration: &Self::Configuration,
state: &Self::State,
request: models::QueryRequest,
) -> Result<JsonResponse<models::ExplainResponse>, ExplainError>;
) -> Result<JsonResponse<models::ExplainResponse>>;

/// Explain a mutation by creating an execution plan
///
/// This function implements the [mutation/explain endpoint](https://hasura.github.io/ndc-spec/specification/explain.html)
/// from the NDC specification.
///
/// The [`ExplainError`] type is provided as a convenience to connector authors, to be used on
/// error.
async fn mutation_explain(
configuration: &Self::Configuration,
state: &Self::State,
request: models::MutationRequest,
) -> Result<JsonResponse<models::ExplainResponse>, ExplainError>;
) -> Result<JsonResponse<models::ExplainResponse>>;

/// Execute a mutation
///
/// This function implements the [mutation endpoint](https://hasura.github.io/ndc-spec/specification/mutations/index.html)
/// from the NDC specification.
///
/// The [`MutationError`] type is provided as a convenience to connector authors, to be used on
/// error.
async fn mutation(
configuration: &Self::Configuration,
state: &Self::State,
request: models::MutationRequest,
) -> Result<JsonResponse<models::MutationResponse>, MutationError>;
) -> Result<JsonResponse<models::MutationResponse>>;

/// Execute a query
///
/// This function implements the [query endpoint](https://hasura.github.io/ndc-spec/specification/queries/index.html)
/// from the NDC specification.
///
/// The [`QueryError`] type is provided as a convenience to connector authors, to be used on
/// error.
async fn query(
configuration: &Self::Configuration,
state: &Self::State,
request: models::QueryRequest,
) -> Result<JsonResponse<models::QueryResponse>, QueryError>;
) -> Result<JsonResponse<models::QueryResponse>>;
}

/// Connectors are set up by values that implement this trait.
Expand All @@ -130,23 +136,26 @@ pub trait Connector {
pub trait ConnectorSetup {
type Connector: Connector;

/// Validate the configuration provided by the user, returning a
/// configuration error or a validated [`Connector::Configuration`].
/// Validate the configuration provided by the user, returning a configuration error or a
/// validated [`Connector::Configuration`].
///
/// The [`ParseError`] type is provided as a convenience to connector authors, to be used on
/// error.
async fn parse_configuration(
&self,
configuration_dir: impl AsRef<Path> + Send,
) -> Result<<Self::Connector as Connector>::Configuration, ParseError>;
) -> Result<<Self::Connector as Connector>::Configuration>;

/// Initialize the connector's in-memory state.
///
/// For example, any connection pools, prepared queries, or other managed
/// resources would be allocated here.
/// For example, any connection pools, prepared queries, or other managed resources would be
/// allocated here.
///
/// In addition, this function should register any connector-specific
/// metrics with the metrics registry.
/// In addition, this function should register any connector-specific metrics with the metrics
/// registry.
async fn try_init_state(
&self,
configuration: &<Self::Connector as Connector>::Configuration,
metrics: &mut prometheus::Registry,
) -> Result<<Self::Connector as Connector>::State, InitializationError>;
) -> Result<<Self::Connector as Connector>::State>;
}
Loading

0 comments on commit 4de7d49

Please sign in to comment.