Skip to content

Conversation

@Oksamies
Copy link
Contributor

(ts-api-react-actions) Enhance error handling in API actions and hooks with user-facing error mapping

Refactor loader functions to enhance error handling and move to different file

Enhance error handling in StrongForm and useFormToaster with user-facing error mapping

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 11-19-_ts-api-react-actions_enhance_error_handling_in_api_actions_and_hooks_with_user-facing_error_mapping

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor Author

Oksamies commented Nov 19, 2025

This was referenced Nov 19, 2025
@Oksamies Oksamies marked this pull request as ready for review November 27, 2025 11:55
import { useApiAction } from "./useApiAction";

/**
* Props for the `ApiAction` component that exposes an async submit handler.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: low value comment

* Props for the `ApiAction` component that exposes an async submit handler.
*/
export interface ApiActionProps<
Params extends object,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Off-scope for this PR, but extends object is a footgun as it doesn't really mean anything since everything except primitives are objects. (I.e. it's not like saying something is a Dict in Python.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was some good reason for this, but can't remember anymore. Was probably something to do with how the ts-api fetch function arguments work


// As of this moment ApiActions sole purpose is to gracefully handle errors from API calls
/**
* Component that wraps an API endpoint in a stable submit callback with mapped errors.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: maybe it's just me but I have hard time grasping this comment.

import { ApiEndpointProps } from "@thunderstore/thunderstore-api";

/**
* Configuration for wiring `useApiAction` to a specific API endpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: generally speaking I don't know if "FooArgs" or "BarProps" benefit that much for having a docstring. "Foo" and "Bar" are more natural places to comment on what the thing actually does (if any extra clarification is needed).

props: ApiEndpointProps<Params, QueryParams, Data>
): Promise<Awaited<Return>> => {
const result = await apiCall(props);
return result as Awaited<Return>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to my IDE this as assertion is not required, and you should avoid unnecessary assertions as they can hide bugs.


interface UseStrongFormProps<
Inputs,
type IsExact<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now here I would welcome a good docstring explaining IsExact, RefinerRequirement, and ErrorMapperRequirement.


export function useStrongForm<
/**
* Configuration for wiring a StrongForm instance to refiners, submitters and lifecycle hooks.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: but instead I get "here be props" and "here be return type" level comments 😔 A hard-knock life.

return mapApiErrorToUserFacingError(error);
};

const mapError: (error: unknown) => SubmissionError =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My IDE flags this for type error, and I don't know why this variable is even used since it's called in only one place, and why it's defined here since the call site comes way later.

const mapError: (error: unknown) => SubmissionError =
props.errorMapper ?? defaultErrorMapper;

useEffect(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole strongForm concept confuses me to the level that I don't even attempt to review it with my fried Friday brain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know, it confuses me nowadays too. But it does work

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be even better though

formatUserFacingError,
} from "@thunderstore/thunderstore-api";

export type UseFormToasterArgs<OnSubmitSuccessDataType, OnSubmitErrorDataType> =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Off-scope but my gut feeling is that the whole useFormToaster is overengineered on the concept level and quite confusing if the point is to just show toasts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not incorrect, but I don't have a solution off the top of my head, probably a worthy non-mission-critical task

@Oksamies Oksamies changed the base branch from 11-19-refactor_api_methods_to_remove_unnecessary_async_await_and_improve_return_handling to graphite-base/1616 December 2, 2025 13:09
@Oksamies Oksamies force-pushed the 11-19-_ts-api-react-actions_enhance_error_handling_in_api_actions_and_hooks_with_user-facing_error_mapping branch from cd40580 to 5ac0d36 Compare December 2, 2025 13:10
@Oksamies Oksamies changed the base branch from graphite-base/1616 to 11-19-refactor_api_methods_to_remove_unnecessary_async_await_and_improve_return_handling December 2, 2025 13:10
@Oksamies Oksamies changed the base branch from 11-19-refactor_api_methods_to_remove_unnecessary_async_await_and_improve_return_handling to graphite-base/1616 December 3, 2025 01:45
@Oksamies Oksamies force-pushed the 11-19-_ts-api-react-actions_enhance_error_handling_in_api_actions_and_hooks_with_user-facing_error_mapping branch from 5ac0d36 to de2572f Compare December 3, 2025 01:46
@Oksamies Oksamies changed the base branch from graphite-base/1616 to 11-19-refactor_api_methods_to_remove_unnecessary_async_await_and_improve_return_handling December 3, 2025 01:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants