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

Add /v2/owners/:ownerAddress/safes to gracefully handle errors #2266

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

Conversation

iamacook
Copy link
Member

@iamacook iamacook commented Jan 16, 2025

Summary

When getting all Safes by owner (/v1/owners/:ownerAddress/safes), every Transaction Service is called. Should one or more throw, the request will as well.

This adds a new endpoint (/v2/owners/:ownerAddress/safes) which returns null for every chain which the Transaction Service threw for.

Changes

  • Add new scaffolding for v2 endpoint, deprecating previous.
  • Wrap Transaction Service requests in Promise.allSettled.
  • Construct all Safe lists from successful requests, logging for errorneous ones.
  • Add appropriate test coverage.

@iamacook iamacook self-assigned this Jan 16, 2025
@iamacook iamacook requested a review from a team as a code owner January 16, 2025 10:31
Copy link
Member

@katspaugh katspaugh left a comment

Choose a reason for hiding this comment

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

Nice. It's good that it still logs when it fails for a given chain.

@PooyaRaki
Copy link
Contributor

I believe we should either return all of a user’s Safes or none at all. As a user, if some of my Safes are missing from a request, I would assume that all have been returned and the missing ones are lost.
The relevance of the above comment depends on the specific use case of the endpoint.

@katspaugh
Copy link
Member

@PooyaRaki I think the proposed change is good for two reasons:

  • In case of an accidental misconfiguration of one of the chains, the other chains will still work
  • Isolating configs per chain will also help isolating issues – when the whole endpoint is down, you have to to triage from scratch

@PooyaRaki
Copy link
Contributor

@katspaugh I agree with you, but I think we should inform users when we’re unable to fetch data from a specific chain due to ongoing issues. Imagine a power user with assets on three different chains—if they see assets on two chains but not the third, they’d likely be confused. If we give them a heads-up about the issue and suggest trying again later, that’s fine. Otherwise, it could be misleading and might hurt their trust in the platform.

@iamacook
Copy link
Member Author

@PooyaRaki, I agree it's important to prioritise clarity for users. However, this approach aligns with the existing behaviour of endpoints that fetch data from every Transaction Service.

Imagine a power user with assets on three different chains—if they see assets on two chains but not the third, they’d likely be confused. If we give them a heads-up about the issue and suggest trying again later, that’s fine. Otherwise, it could be misleading and might hurt their trust in the platform.

As we're fetching data from every chain, if a particular Transaction Service throws, we lack clarity as to whether the user has Safes on that chain, so it's potentially confusing either way.

One alternative could be to return null for the affected chain(s) and explicitly display a warning that Safes couldn't be fetched there.

What are your thoughts? cc @katspaugh

@PooyaRaki
Copy link
Contributor

One alternative could be to return null for the affected chain(s) and explicitly display a warning that Safes couldn't be fetched there.

@iamacook

Yes, that’s what I was saying—we should display a warning indicating that Safes couldn’t be loaded there. Regarding returning null, what do we return if the user doesn’t have a Safe on a chain? The client needs to differentiate between an error and the absence of a Safe on a chain to display the appropriate error message.
Additionally, we need to ensure that the client properly handles this case before deploying this PR to production.

@iamacook
Copy link
Member Author

Regarding returning null, what do we return if the user doesn’t have a Safe on a chain?

An empty array indicates no Safes are owned on a given chain when a request is successful. This PR, however, excludes the chain in question if the request fails.

I'd like to emphasise that returning null would strictly indicate that a request failed, leaving us uncertain whether Safes are (or aren't) owned on the affected chain.

we should display a warning indicating that Safes couldn’t be loaded there. Regarding returning null, what do we return if the user doesn’t have a Safe on a chain

Let's see what @katspaugh thinks about this, as implementing such changes would require client updates, whereas this PR is intended as a quick fix.

@katspaugh
Copy link
Member

An empty array if no safes or null if a chain threw sounds good. That'd be a breaking change so we'll have to adjust the frontend.

@PooyaRaki
Copy link
Contributor

I’d be happy to approve it, provided we ensure that our users are properly notified about the error. As an end user, I wouldn’t want to see my assets disappear simply because certain chains are experiencing issues.

Comment on lines 25 to 33
@ApiOkResponse({
schema: {
type: 'object',
additionalProperties: {
type: 'array',
items: { type: 'string' },
},
},
})
Copy link
Member Author

Choose a reason for hiding this comment

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

The types were previously incorrect.

This cannot be set in a class as the dynamic properties are top-level.

@@ -453,4 +457,327 @@ describe('Owners Controller (Unit)', () => {
.expect({ statusCode: 502, message: 'Bad gateway' });
});
});

describe('GET all safes by owner address', () => {
Copy link
Member Author

Choose a reason for hiding this comment

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

Apart from the graceful handling case, these duplicate the above for the v2 endpoint.

@iamacook
Copy link
Member Author

An empty array if no safes or null if a chain threw sounds good. That'd be a breaking change so we'll have to adjust the frontend.

I've added a v2 endpoint implementing the above. Please lmk what you think, @PooyaRaki @katspaugh

@iamacook iamacook changed the title Gracefully handle errors when getting all Safes by owner Add /v2/owners/:ownerAddress/safes to gracefully handle errors Jan 20, 2025
@iamacook iamacook changed the title Add /v2/owners/:ownerAddress/safes to gracefully handle errors Add /v2/chains/:chainId/owners/:ownerAddress/safes to gracefully handle errors Jan 20, 2025
@iamacook iamacook changed the title Add /v2/chains/:chainId/owners/:ownerAddress/safes to gracefully handle errors Add /v2/owners/:ownerAddress/safes to gracefully handle errors Jan 20, 2025
Copy link
Member

@katspaugh katspaugh left a comment

Choose a reason for hiding this comment

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

Thanks!

},
},
})
@Get('/v2/owners/:ownerAddress/safes')
Copy link
Contributor

Choose a reason for hiding this comment

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

The v2 endpoint should be stored in another controller, ideally the folder structure would look like:
src/routes/owners/v1/owners.controller.ts
src/routes/owners/v2/owners.controller.ts

But for now, if you think restructuring the whole component is outside the scope of this PR we could just create a new v2 file in the same directory:
src/routes/owners/owners.controller.v1.ts
src/routes/owners/owners.controller.v2.ts

The ideal solution is the first option, but I’m also satisfied with the second.

Copy link
Member Author

Choose a reason for hiding this comment

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

As per discussion, this was adjusted in 9121170:

There are now versioned controllers: OwnersControllerV1 and OwnersControllerV2 (owners.controller.v*.ts). As the service/repository methods are controller agnostic, however, they retain the deprecated__ prefix, with JSDoc markers.

@iamacook
Copy link
Member Author

Do you think we should copy this behaviour to other endpoints that query all Transaction Services?

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.

3 participants