Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the error handling for HTTP client so consumers can trigger appropriate behavior #793

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

passuied
Copy link

@passuied passuied commented Mar 14, 2025

Description

Improve the error handling for HTTP client so consumers can trigger appropriate behavior

Issue reference

We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.

Please reference the issue this PR will close: #794

Checklist

Please make sure you've completed the relevant tasks for this PR, out of the following list:

  • Code compiles correctly
  • Created/updated tests
  • Extended the documentation (n/a)

@passuied passuied requested review from a team as code owners March 14, 2025 21:55
@passuied passuied force-pushed the feature/improve-client-http-error-details branch from 7457f5a to 18cc895 Compare March 14, 2025 22:07
Copy link
Contributor

@elena-kolevska elena-kolevska left a comment

Choose a reason for hiding this comment

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

I feel like instead of modifying the genericDaprInternalError class with http properties that are not always relevant, we should extend it to a http specific class, something like:
class DaprHttpError(DaprInternalError):

@passuied
Copy link
Author

I feel like instead of modifying the genericDaprInternalError class with http properties that are not always relevant, we should extend it to a http specific class, something like:
class DaprHttpError(DaprInternalError):

I like it. What about including the response object in the exception then? I was hesitating about it but didn't want to couple it.

Signed-off-by: Patrick Assuied <[email protected]>
Signed-off-by: Patrick Assuied <[email protected]>
@passuied passuied requested a review from elena-kolevska March 17, 2025 19:56
Comment on lines 108 to 113
if (error_body is None or len(error_body) == 0) and response.status == 404:
return DaprInternalError('Not Found', ERROR_CODE_DOES_NOT_EXIST)
return DaprHttpError(
error_code=ERROR_CODE_DOES_NOT_EXIST,
status_code=response.status,
reason=response.reason,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this logic should be encapsulated in the error class itself. The error class would only receive the response object and it would create the error code, message and everything else based on it.

Copy link
Author

@passuied passuied Mar 19, 2025

Choose a reason for hiding this comment

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

Unfortunately, calling response.read() is async so I'm not sure we can use it in a constructor... copilot is recommending using asyncio.run() but I'm not sure that's a good idea... I'm worried about the negative performance side effects. There's also a dependency on self._serializer...
All in all, I'm not sure if the encapsulation is worth it...

This is the best I could do below but I don't like the dependency to DaprHttpClient instance.

async def from_response(http_client: DaprHttpClient, response: aiohttp.ClientResponse):
        error_info = None
        try:
            error_body = await response.read()
            if (error_body is None or len(error_body) == 0) and response.status == 404:
                return DaprHttpError(
                    error_code=ERROR_CODE_DOES_NOT_EXIST,
                    status_code=response.status,
                    reason=response.reason,
                )
            error_info = http_client._serializer.deserialize(error_body)
        except Exception:
            return DaprHttpError(
                error_code=ERROR_CODE_UNKNOWN,
                raw_response_bytes=error_body,
                status_code=response.status,
                reason=response.reason,
            )

        if error_info and isinstance(error_info, dict):
            message = error_info.get('message')
            error_code = error_info.get('errorCode') or ERROR_CODE_UNKNOWN
            return DaprHttpError(
                message=message,
                error_code=error_code,
                raw_response_bytes=error_body,
                status_code=response.status,
                reason=response.reason,
            )

        return DaprHttpError(
            error_code=ERROR_CODE_UNKNOWN,
            raw_response_bytes=error_body,
            status_code=response.status,
            reason=response.reason,
        )

Copy link
Author

Choose a reason for hiding this comment

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

I have refactored the code and I have come up with a good compromise (I hope). Please let me know

@passuied passuied requested a review from elena-kolevska March 19, 2025 04:43
Signed-off-by: Patrick Assuied <[email protected]>
Signed-off-by: Patrick Assuied <[email protected]>
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.

[FEATURE REQUEST] Improve Dapr HTTP client error handling
2 participants