Skip to content

Conversation

@bitgopatmcl
Copy link
Contributor

@bitgopatmcl bitgopatmcl commented Apr 26, 2022

This PR does two main things:

  1. Remove the response library from several places, cleaning up several parts of the codebase
  2. Allow the response library to still be used for creating http-agnostic service functions

On the second point, I tried a few approaches before ultimately punting on it and just extending the "decode request and encode response" function in express-wrapper to handle either raw HTTP status codes or response ones.

@bitgopatmcl bitgopatmcl force-pushed the response-in-express-wrapper branch 2 times, most recently from 30b74f7 to 29be96e Compare April 28, 2022 15:13
@bitgopatmcl bitgopatmcl changed the title factor response library out of io-ts-http change the way response is used Apr 28, 2022

export type RouteHandler<R extends HttpRoute> =
| ServiceFunction<R>
| { middleware: express.RequestHandler[]; function: ServiceFunction<R> };
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change ended up in here from when I was attempting larger overhauls of the middleware system. I can revert this but would at least like to keep the ability to specify a bare service function without using a single element array.

Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like a good usability win, but oh boy do I hate irregularities and added complexity 🙈

We'll probably leave this feat in but def don't want to become the kitchen sink

@bitgopatmcl bitgopatmcl marked this pull request as ready for review April 28, 2022 15:20
@bitgopatmcl bitgopatmcl requested a review from a team April 28, 2022 15:20
}

const isHttpVerb = (verb: string): verb is 'get' | 'put' | 'post' | 'delete' =>
({ get: 1, put: 1, post: 1, delete: 1 }.hasOwnProperty(verb));
Copy link
Contributor

Choose a reason for hiding this comment

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

hasOwnProperty seems the scenic route here, in this low-level library I've been focused on speed, simplicity, and reliability.

Whereas this implementation involves function calls, standard library implementations, iterating, garbage collection, can we use an approach that can short-circuit and use less memory? Something like

verb === 'get' || verb === 'put' || verb === 'post' || verb === 'delete'

?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also nit: when we enable eslint there's a fair chance this rule makes the cut https://eslint.org/docs/rules/no-use-before-define

which would error here because isHttpVerb is not defined before use on line 33

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In theory, the || chain is O(n) and hasOwnProperty can be O(log n). In practice, it's 4 items so wouldn't be surprised if the || chain is faster.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

function calls, standard library implementations, iterating, garbage collection

A Sufficiently Smart Compiler™ could notice the object literal is static so not allocate it each time and devirtualize the hasOwnProperty call. I have no idea what v8/node actually does under the hood though.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh my, you are quite right!

Now I want to benchmark 😅

image

Not sure how accurate this is though

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah the main thing I see is that the function param is hardcoded to delete in that benchmark and so it might be optimized in ways that the general version isn't, or maybe not idk.

@bitgopatmcl bitgopatmcl force-pushed the response-in-express-wrapper branch 2 times, most recently from 901044d to 31d415d Compare April 28, 2022 18:30
async (req, res) => {
const maybeRequest = httpRoute.request.decode(req);
if (maybeRequest._tag === 'Left') {
console.log('Request failed to decode');

Choose a reason for hiding this comment

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

will people be using this function? Cuz this would log in their console right which is something they might not want

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function is intended to be package-internal. It's exported from this file but not re-exported from index. Does express have some kind of logging system? I don't see one skimming the docs.

Copy link
Contributor

Choose a reason for hiding this comment

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

While I ponder this, I will point out the 12-factor way is "log to stdout/stderr"

https://12factor.net/logs

Choose a reason for hiding this comment

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

Ok yeah its probably fine then

Copy link
Contributor

Choose a reason for hiding this comment

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

I did come across this over the weekend, is it destiny? or inapplicable

image

https://www.lpalmieri.com/posts/error-handling-rust/

Here we are handling the error on the developer's behalf, and it would be transparent if not for this error. According to this advice, logging here is the proper action

@bitgopatmcl bitgopatmcl force-pushed the response-in-express-wrapper branch from 31d415d to eb5b63e Compare April 28, 2022 20:41
'hello.world': {
put: [routeMiddleware, CreateHelloWorld],
get: [GetHelloWorld],
put: { middleware: [routeMiddleware], function: CreateHelloWorld },
Copy link
Contributor

Choose a reason for hiding this comment

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

Seeing it here, is function the clearest and least-ambiguous key? What about handler?

I see the word handler used in this documentation https://expressjs.com/en/guide/using-middleware.html
but I should mention this was a quick search and I'm not sure this is the right terminology.

I feel like we can be more precise in how the function will be used, instead of what it is

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noticed it is inconsistently named in the codebase too, so this would clean it up.

Copy link
Contributor

@ericcrosson-bitgo ericcrosson-bitgo left a comment

Choose a reason for hiding this comment

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

I like this, and I think we should punt the discussion on logging so we can get a clear vision for the entire family of packages to avoid waffling at each log-site.

Only outstanding comment is the one about renaming function -> handler, what do you think there?

ryan-bitgo
ryan-bitgo previously approved these changes Apr 28, 2022
@bitgopatmcl bitgopatmcl force-pushed the response-in-express-wrapper branch from eb5b63e to 5a7dc31 Compare April 29, 2022 13:22
@ericcrosson-bitgo
Copy link
Contributor

@bitgopatmcl I see a merge conflict

@bitgopatmcl bitgopatmcl force-pushed the response-in-express-wrapper branch from 5a7dc31 to 7dd2fff Compare April 29, 2022 15:25
Copy link
Contributor

@ericcrosson-bitgo ericcrosson-bitgo left a comment

Choose a reason for hiding this comment

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

Looks good to me 🚢

@bitgopatmcl bitgopatmcl merged commit 8c2b2f9 into BitGo:beta Apr 29, 2022
@bitgopatmcl bitgopatmcl deleted the response-in-express-wrapper branch April 29, 2022 15:27
@github-actions
Copy link

🎉 This PR is included in version 1.0.0-beta.6 🎉

The release is available on npm package (@beta dist-tag)

Your semantic-release bot 📦🚀

@github-actions
Copy link

🎉 This PR is included in version 0.2.0-beta.5 🎉

The release is available on npm package (@beta dist-tag)

Your semantic-release bot 📦🚀

@github-actions
Copy link

🎉 This PR is included in version 0.2.0-beta.1 🎉

The release is available on npm package (@beta dist-tag)

Your semantic-release bot 📦🚀

@github-actions
Copy link

🎉 This PR is included in version 0.2.0-beta.5 🎉

The release is available on npm package (@beta dist-tag)

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants