Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Refactor http client #113

Merged
merged 20 commits into from
Dec 20, 2023
Merged

Refactor http client #113

merged 20 commits into from
Dec 20, 2023

Conversation

kirahsapong
Copy link
Contributor

@kirahsapong kirahsapong commented Dec 7, 2023

Summary

This PR addresses #111

It adds custom error types including RequestError, ResponseError, ValidationError, custom validation error types including InvalidDidError and InvalidServiceEndpointError.

The http-client is refactored to throw a custom error type in case of a failure, and return data only in case of success.

This PR only introduces more narrow custom error types for ValidationErrors. We can track adding more narrow custom error types for request and response errors here.

Copy link

changeset-bot bot commented Dec 7, 2023

🦋 Changeset detected

Latest commit: 85e541a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@tbdex/http-client Minor
@tbdex/http-server Minor
@tbdex/protocol Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@kirahsapong kirahsapong requested a review from diehuxx December 7, 2023 03:24
@kirahsapong kirahsapong mentioned this pull request Dec 7, 2023
try {
pfiServiceEndpoint = await TbdexHttpClient.getPfiServiceEndpoint(pfiDid)
} catch(e) {
throw new RequestError({ message: e['message'], recipientDid: pfiDid, cause: e })
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than catching and throwing the exception here, would it be more wise to throw the exception from within the TbdexHttpClient.getPfiServiceEndpoint function? This is the beauty of using exceptions for error cases, rather than the return type, in that we can bubble-up the exceptions throughout n-number of callstack layers

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch yep!

@KendallWeihe
Copy link
Contributor

Nice!

Embrace debate. I think it would be wise to be more fine-grained in our custom exceptions, with names that match the semantic failure. We're exchanging a design pattern where the return type has errors for using exceptions, which means the consuming developer is expected to key-off-of the given exceptions to drive their own business logic. By using a more-general exception, such as RequestError, the developer would have to do string-based conditionals based on the exceptions message. For example, this is how the current DX would look like...

try {
  await TbdexHttpClient.getOfferings({ pfiDid: 'hehetroll' })
} catch (e) {
  if (e.message.include('invalidDid')) { // this line
    console.log('This was an issue with the given DID')
  } else if (e.message.include('has no PFI service entry')) { // and this line
    console.log('This was a PFI discovery exception')
  }
}

But, if we fine-grained RequestError into two new exceptions, let's call them InvalidPfiDid and EmptyPfiServiceEndpoint (I think maybe we can do better on the names, just shooting from the hip), then the DX would look like this...

try {
  await TbdexHttpClient.getOfferings({ pfiDid: 'hehetroll' })
} catch (e) {
  if (e instanceof InvalidPfiDid) {
    console.log('This was an issue with the given DID')
  } else if (e instanceof EmptyPfiServiceEndpoint) {
    console.log('This was a PFI discovery exception')
  } 
}

With this approach, the general heuristic would be one-custom-exception-per-test-case

@kirahsapong kirahsapong force-pushed the origin/refactor-http-client branch from bdfeb27 to 60e6ecb Compare December 7, 2023 17:16
@mistermoe
Copy link
Member

@kirahsapong we thinking about refactoring the rest of http-client in this PR or refactoring 1 method per PR?

@mistermoe
Copy link
Member

@KendallWeihe could we address what you're bringing up by introducing a kind property to RequestError?

@KendallWeihe
Copy link
Contributor

@KendallWeihe could we address what you're bringing up by introducing a kind property to RequestError?

Could, and think it would be fine, but my intuition is against it.

If we did, then we would want to define a type as a set of string literals, in the same way we do MessageKind. This way, we're still leveraging the static typing of TypeScript.

I think it's good for the DX, in that it would further add a layer of semantic reasoning to the developer of whether or not the given kind of exception was caused during the requesting or during the responding. But also, it's restrictive in that same sense in that certain kinds of exceptions may span both requesting and responding, in which case the additional hierarchy of categorization is useless overhead and only serves to confuse. I guess basically my point is, it's abstraction which doesn't offer net positive return.

I think it better to have a flattened set of exceptions, where the name of the exception is the valuable nugget of experience.

But, also, it's splitting hairs, so just do it one way or the other and it's fine 😆

@kirahsapong
Copy link
Contributor Author

@mistermoe good point might be nice to do 1 per PR to keep the review a bit tighter

@kirahsapong
Copy link
Contributor Author

@KendallWeihe agree with your reasoning!

@kirahsapong kirahsapong marked this pull request as draft December 8, 2023 19:01
@kirahsapong kirahsapong force-pushed the origin/refactor-http-client branch from 7851abe to 056b044 Compare December 18, 2023 19:30
@kirahsapong kirahsapong marked this pull request as ready for review December 18, 2023 19:56
@kirahsapong
Copy link
Contributor Author

Added more info to the PR summary ✨

Copy link
Contributor

@KendallWeihe KendallWeihe left a comment

Choose a reason for hiding this comment

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

🎉

Copy link
Member

Choose a reason for hiding this comment

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

nice!

@@ -27,7 +28,7 @@ export class TbdexHttpClient {
* @throws if recipient DID resolution fails
* @throws if recipient DID does not have a PFI service entry
*/
static async sendMessage<T extends MessageKind>(opts: SendMessageOptions<T>): Promise<HttpResponse | ErrorResponse> {
static async sendMessage<T extends MessageKind>(opts: SendMessageOptions<T>): Promise<HttpResponse> {
Copy link
Member

Choose a reason for hiding this comment

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

thoughts on just returning Promise<void> here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch thanks!

suppose we can remove DataResponse from our types, with a lil bit of tech debt to refactor our http-server tests to remove our HttpResponse and ErrorResponse in a follow up, yeah?

Copy link
Member

Choose a reason for hiding this comment

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

yup good idea!

Copy link
Contributor

github-actions bot commented Dec 19, 2023

TBDocs Report

✅ No errors or warnings

@tbdex/protocol

  • Project entry file: packages/protocol/src/main.ts

@tbdex/http-client

  • Project entry file: packages/http-client/src/main.ts

@tbdex/http-server

  • Project entry file: packages/http-server/src/main.ts

TBDocs Report Updated at 2023-12-20T19:01:22Z 85e541a

@kirahsapong kirahsapong force-pushed the origin/refactor-http-client branch from ad7978a to 8153e4a Compare December 19, 2023 20:08
@mistermoe
Copy link
Member

@kirahsapong as much as i want to use msw, i think it may be in our best interests to stub fetch instead. I've been working on updating how we run browser tests, but even with those changes, conditionally switching between the msw import for node vs. browser is going to be tricky.

Did you have an approach in mind for conditionally switching between import { setupWorker } from 'msw/browser' and import { setupServer } from 'msw/node'?

Otherwise, i think we can follow this example from web5-js to mock fetch!

@kirahsapong
Copy link
Contributor Author

@kirahsapong as much as i want to use msw, i think it may be in our best interests to stub fetch instead. I've been working on updating how we run browser tests, but even with those changes, conditionally switching between the msw import for node vs. browser is going to be tricky.

Did you have an approach in mind for conditionally switching between import { setupWorker } from 'msw/browser' and import { setupServer } from 'msw/node'?

Otherwise, i think we can follow this example from web5-js to mock fetch!

yeah have the same concern! my initial instinct is the overhead to switch betwixt will outweigh any benefit when all we're using msw for is stubbing fetch. i'm good to switcheroo!

Copy link
Contributor

@phoebe-lew phoebe-lew left a comment

Choose a reason for hiding this comment

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

nice nice, can cut a new release 🚀

headers : response.headers,
errors : responseBody.errors
}
if (!response.ok) {
Copy link
Contributor

Choose a reason for hiding this comment

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

so if this function returns nothing, that means the response was ok?

Copy link
Member

Choose a reason for hiding this comment

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

yee

@mistermoe
Copy link
Member

oh yeah! last thing to note would be that we probably should add a changeset to trigger a version bump. we should highlight that this is a breaking change and send the changelog over to devrel incase they've built any examples or written guides using TbdexHttpClient

@kirahsapong kirahsapong merged commit 9e1015e into main Dec 20, 2023
7 checks passed
@kirahsapong kirahsapong deleted the origin/refactor-http-client branch December 20, 2023 19:36
diehuxx pushed a commit that referenced this pull request Jan 4, 2024
* main:
  Remove HttpResponse and ErrorResponse from `http-client` types (#124)
  Refactor http client to introduce custom error types (#113)
  Finish validating rfq against provided offering (#120)
  Generates the HTML to publish to GH Pages (#116)
  http-server fixes + some tests (#83)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants