Skip to content

Commit

Permalink
feat(api): handle subscribe feed error
Browse files Browse the repository at this point in the history
  • Loading branch information
ymgyt committed Feb 22, 2024
1 parent 1a9b81d commit 90c47d3
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 28 deletions.
35 changes: 25 additions & 10 deletions crates/synd_api/src/gql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod mutation;
use async_graphql::{EmptySubscription, Schema, SchemaBuilder};
pub use mutation::Mutation;

use crate::{principal::Principal, usecase};
use crate::{gql::mutation::ResponseCode, principal::Principal, usecase};

pub mod object;
pub mod scalar;
Expand Down Expand Up @@ -62,22 +62,37 @@ where
{
fn extend(&self) -> async_graphql::Error {
async_graphql::Error::new(format!("{self}")).extend_with(|_, ext| match self {
usecase::Error::Usecase(_) => ext.set("code", "TODO"),
usecase::Error::Unauthorized(_) => ext.set("code", "UNAUTHORIZED"),
usecase::Error::Repository(_) => ext.set("code", "INTERNAL"),
usecase::Error::Usecase(_) => unreachable!(),
usecase::Error::Unauthorized(_) => ext.set("code", ResponseCode::Unauthorized),
usecase::Error::Repository(_) => ext.set("code", ResponseCode::InternalError),
})
}
}

impl async_graphql::ErrorExtensions for usecase::FetchEntriesError {
fn extend(&self) -> async_graphql::Error {
async_graphql::Error::new(format!("{self}"))
.extend_with(|_, ext| ext.set("code", ResponseCode::InternalError))
}
}

impl async_graphql::ErrorExtensions for usecase::FetchSubscribedFeedsError {
fn extend(&self) -> async_graphql::Error {
async_graphql::Error::new(format!("{self}"))
.extend_with(|_, ext| ext.set("code", ResponseCode::InternalError))
}
}

macro_rules! run_usecase {
($usecase:ty, $cx:expr, $input:expr) => {{
($usecase:ty, $cx:expr, $input:expr,$err_handle:expr) => {{
let runtime = $cx.data_unchecked::<crate::usecase::Runtime>();
let err_handle = $err_handle;

runtime
.run::<$usecase, _, _>($cx, $input)
.await
.map_err(|err| async_graphql::ErrorExtensions::extend(&err))
.map(Into::into)
match runtime.run::<$usecase, _, _>($cx, $input).await {
Ok(output) => Ok(output.into()),
Err($crate::usecase::Error::Usecase(uc_err)) => err_handle(uc_err),
Err(err) => Err(async_graphql::ErrorExtensions::extend(&err)),
}
}};
}

Expand Down
24 changes: 21 additions & 3 deletions crates/synd_api/src/gql/mutation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use async_graphql::{Context, Enum, Interface, Object, SimpleObject};

use crate::{
gql::run_usecase,
usecase::{SubscribeFeed, UnsubscribeFeed},
usecase::{SubscribeFeed, SubscribeFeedError, UnsubscribeFeed},
};

pub mod subscribe_feed;
Expand All @@ -14,6 +14,8 @@ pub enum ResponseCode {
Ok,
/// Principal does not have enough permissions
Unauthorized,
/// Given url is not valid feed url
InvalidFeedUrl,
/// Something went wrong
InternalError,
}
Expand All @@ -37,6 +39,18 @@ impl ResponseStatus {
code: ResponseCode::Unauthorized,
}
}

fn invalid_feed_url() -> Self {
Self {
code: ResponseCode::InvalidFeedUrl,
}
}

fn internal() -> Self {
Self {
code: ResponseCode::InternalError,
}
}
}

#[allow(clippy::large_enum_variant)]
Expand Down Expand Up @@ -67,7 +81,9 @@ impl Mutation {
cx: &Context<'_>,
input: subscribe_feed::SubscribeFeedInput,
) -> async_graphql::Result<subscribe_feed::SubscribeFeedResponse> {
run_usecase!(SubscribeFeed, cx, input)
run_usecase!(SubscribeFeed, cx, input, |err: SubscribeFeedError| Ok(
err.into()
))
}

/// Unsubscribe feed
Expand All @@ -77,6 +93,8 @@ impl Mutation {
cx: &Context<'_>,
input: unsubscribe_feed::UnsubscribeFeedInput,
) -> async_graphql::Result<unsubscribe_feed::UnsubscribeFeedResponse> {
run_usecase!(UnsubscribeFeed, cx, input)
run_usecase!(UnsubscribeFeed, cx, input, |err: anyhow::Error| Ok(
err.into()
))
}
}
26 changes: 25 additions & 1 deletion crates/synd_api/src/gql/mutation/subscribe_feed.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use async_graphql::{InputObject, Object, Union};
use synd_feed::feed::parser::FetchFeedError;

use crate::{
gql::{
mutation::ResponseStatus,
object::{self, Feed},
},
usecase,
usecase::{self, SubscribeFeedError as UsecaseSubscribeFeedError},
};

#[derive(InputObject)]
Expand Down Expand Up @@ -78,3 +79,26 @@ impl From<usecase::Output<usecase::SubscribeFeedOutput>> for SubscribeFeedRespon
})
}
}

impl From<UsecaseSubscribeFeedError> for SubscribeFeedResponse {
fn from(err: UsecaseSubscribeFeedError) -> Self {
SubscribeFeedResponse::Error(err.into())
}
}

impl From<UsecaseSubscribeFeedError> for SubscribeFeedError {
fn from(err: UsecaseSubscribeFeedError) -> Self {
match err {
UsecaseSubscribeFeedError::FetchFeed(fetch_err) => match fetch_err {
FetchFeedError::InvalidFeed(kind) => Self {
status: ResponseStatus::invalid_feed_url(),
message: format!("{kind}"),
},
fetch_err => Self {
status: ResponseStatus::internal(),
message: format!("{fetch_err}"),
},
},
}
}
}
9 changes: 9 additions & 0 deletions crates/synd_api/src/gql/mutation/unsubscribe_feed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ impl From<ResponseStatus> for UnsubscribeFeedResponse {
}
}

impl From<anyhow::Error> for UnsubscribeFeedResponse {
fn from(err: anyhow::Error) -> Self {
UnsubscribeFeedResponse::Error(UnsubscribeFeedError {
status: ResponseStatus::internal(),
message: format!("{err}"),
})
}
}

impl From<usecase::Output<usecase::UnsubscribeFeedOutput>> for UnsubscribeFeedResponse {
fn from(_output: usecase::Output<usecase::UnsubscribeFeedOutput>) -> Self {
UnsubscribeFeedResponse::Success(UnsubscribeFeedSuccess {
Expand Down
16 changes: 12 additions & 4 deletions crates/synd_api/src/gql/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use crate::{
run_usecase,
},
usecase::{
FetchEntries, FetchEntriesInput, FetchEntriesOutput, FetchSubscribedFeeds,
FetchSubscribedFeedsInput, FetchSubscribedFeedsOutput, Output,
FetchEntries, FetchEntriesError, FetchEntriesInput, FetchEntriesOutput,
FetchSubscribedFeeds, FetchSubscribedFeedsError, FetchSubscribedFeedsInput,
FetchSubscribedFeedsOutput, Output,
},
};

Expand All @@ -34,7 +35,12 @@ impl Subscription {
};
let Output {
output: FetchSubscribedFeedsOutput { feeds },
} = run_usecase!(FetchSubscribedFeeds, cx, input)?;
} = run_usecase!(
FetchSubscribedFeeds,
cx,
input,
|err: FetchSubscribedFeedsError| Err(async_graphql::ErrorExtensions::extend(&err))
)?;

let has_next = feeds.len() > first;
let mut connection = Connection::new(has_prev, has_next);
Expand Down Expand Up @@ -67,7 +73,9 @@ impl Subscription {
};
let Output {
output: FetchEntriesOutput { entries, feeds },
} = run_usecase!(FetchEntries, cx, input)?;
} = run_usecase!(FetchEntries, cx, input, |err: FetchEntriesError| Err(
async_graphql::ErrorExtensions::extend(&err)
))?;

let has_next = entries.len() > first;
let mut connection = Connection::new(has_prev, has_next);
Expand Down
10 changes: 7 additions & 3 deletions crates/synd_api/src/usecase/fetch_entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use std::{cmp::Ordering, collections::HashMap, sync::Arc};

use futures_util::{stream::FuturesUnordered, StreamExt};
use synd_feed::{
feed::{cache::FetchCachedFeed, parser::ParserError},
feed::{cache::FetchCachedFeed, parser::FetchFeedError},
types::{self, EntryId},
};
use thiserror::Error;

use crate::{
principal::Principal,
Expand All @@ -28,12 +29,15 @@ pub struct FetchEntriesOutput {
pub feeds: HashMap<types::FeedUrl, types::FeedMeta>,
}

#[derive(Error, Debug)]
pub enum FetchEntriesError {}

impl Usecase for FetchEntries {
type Input = FetchEntriesInput;

type Output = FetchEntriesOutput;

type Error = anyhow::Error;
type Error = FetchEntriesError;

fn new(make: &MakeUsecase) -> Self {
Self {
Expand Down Expand Up @@ -66,7 +70,7 @@ impl Usecase for FetchEntries {

let mut feed_metas = HashMap::new();
let mut entries = Vec::with_capacity(urls.len() * 2);
let mut handle_feed = |feed: Result<Arc<types::Feed>, ParserError>| {
let mut handle_feed = |feed: Result<Arc<types::Feed>, FetchFeedError>| {
let feed = match feed {
Ok(feed) => feed,
Err(err) => {
Expand Down
6 changes: 5 additions & 1 deletion crates/synd_api/src/usecase/fetch_subscribed_feeds.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;

use synd_feed::{feed::cache::FetchCachedFeed, types};
use thiserror::Error;

use crate::{
principal::Principal,
Expand All @@ -23,12 +24,15 @@ pub struct FetchSubscribedFeedsOutput {
pub feeds: Vec<Arc<types::Feed>>,
}

#[derive(Error, Debug)]
pub enum FetchSubscribedFeedsError {}

impl Usecase for FetchSubscribedFeeds {
type Input = FetchSubscribedFeedsInput;

type Output = FetchSubscribedFeedsOutput;

type Error = anyhow::Error;
type Error = FetchSubscribedFeedsError;

fn new(make: &MakeUsecase) -> Self {
Self {
Expand Down
9 changes: 6 additions & 3 deletions crates/synd_api/src/usecase/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
mod subscribe_feed;
pub use subscribe_feed::{SubscribeFeed, SubscribeFeedInput, SubscribeFeedOutput};
pub use subscribe_feed::{
SubscribeFeed, SubscribeFeedError, SubscribeFeedInput, SubscribeFeedOutput,
};

mod unsubscribe_feed;
pub use unsubscribe_feed::{UnsubscribeFeed, UnsubscribeFeedInput, UnsubscribeFeedOutput};

mod fetch_subscribed_feeds;
pub use fetch_subscribed_feeds::{
FetchSubscribedFeeds, FetchSubscribedFeedsInput, FetchSubscribedFeedsOutput,
FetchSubscribedFeeds, FetchSubscribedFeedsError, FetchSubscribedFeedsInput,
FetchSubscribedFeedsOutput,
};

mod fetch_entries;
pub use fetch_entries::{FetchEntries, FetchEntriesInput, FetchEntriesOutput};
pub use fetch_entries::{FetchEntries, FetchEntriesError, FetchEntriesInput, FetchEntriesOutput};

use tracing::error;

Expand Down
16 changes: 13 additions & 3 deletions crates/synd_api/src/usecase/subscribe_feed.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std::sync::Arc;

use synd_feed::{feed::cache::FetchCachedFeed, types::Feed};
use synd_feed::{
feed::{cache::FetchCachedFeed, parser::FetchFeedError},
types::Feed,
};
use synd_o11y::metric;
use thiserror::Error;

use crate::{
principal::Principal,
Expand All @@ -24,12 +28,18 @@ pub struct SubscribeFeedOutput {
pub feed: Arc<Feed>,
}

#[derive(Error, Debug)]
pub enum SubscribeFeedError {
#[error("fetch feed error: {0}")]
FetchFeed(FetchFeedError),
}

impl Usecase for SubscribeFeed {
type Input = SubscribeFeedInput;

type Output = SubscribeFeedOutput;

type Error = anyhow::Error;
type Error = SubscribeFeedError;

fn new(make: &super::MakeUsecase) -> Self {
Self {
Expand Down Expand Up @@ -60,7 +70,7 @@ impl Usecase for SubscribeFeed {
.fetch_feed
.fetch_feed(url.clone())
.await
.map_err(|err| super::Error::Usecase(anyhow::Error::from(err)))?;
.map_err(|err| super::Error::Usecase(SubscribeFeedError::FetchFeed(err)))?;

tracing::debug!("{:?}", feed.meta());

Expand Down

0 comments on commit 90c47d3

Please sign in to comment.