这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@danielgtaylor
Copy link
Owner

@danielgtaylor danielgtaylor commented Feb 1, 2024

This fairly substantial PR is an attempt to reduce the dependencies needed to use Huma v2. It uses a combination of building features in-house, copying small utility functions rather than including big deps, and figuring out different approaches to not need to rely on certain de facto standard deps. Read on for details:

  1. github.com/spf13/viper was used for binding environment variables to command options. Instead, the code now manually checks for these env vars and sets the default on the command option as necessary, no longer needing viper which pulls in tons of deps.
  2. github.com/goccy/go-yaml was used to serialize the OpenAPI to YAML & JSON. It supports the nice ,inline feature for extensions but is large and pulls in a bunch of other deps. Instead, I built a utility function to help with marshalling JSON using custom MarshalJSON() ([]byte, error) methods for the OpenAPI objects. Then I've embedded the tiny json2yaml code that converts the JSON string to a YAML string, allowing me to completely remove any YAML dependency from the project.
  3. The examples brought in a bunch of unnecessary dependencies. They have their own go.mod now, further reducing the main Huma v2 library's go.mod.
  4. github.com/danielgtaylor/huma v1 was used for benchmarking and examples. The benchmark is now commented out as it's no longer hugely relevant.
  5. An example field transformer was pulling in github.com/danielgtaylor/shorthand/v2 and github.com/danielgtaylor/mexpr. This is now moved to the examples directory where it belongs as it isn't used anywhere and is just a toy to show the possibilities.
  6. I was pulling in like 50mb of code to support title casing type names in the registry, but in practice it only impacts simple scalar types like intInt. Instead, this is now completely replaced with a simple unicode-aware uppercase on the first char. This saves pulling down a ton of deps code, over 99% of which was unused.
  7. The idn-hostname format validator doesn't work and is not used, so the attempt to parse such hostnames is removed for now. If this feature is useful/needed I'll add it back in, but will need some failing examples for tests. This used the same deps as above, so saves a good chunk.
  8. The UUID validator from golang.org/google/uuid is now embedded. We don't need the entire library just to check if a UUID is valid.
  9. There are a few other various small changes, like tests not relying on protobuf.

Starting a brand new project with Huma using the huma.rocks tutorial but with Go 1.22's built-in router (so no Chi external router dependency) you can see quite a difference in dependencies that are pulled down:

module example.com/demo

go 1.22

require github.com/danielgtaylor/huma/v2 v2.3.0

require (
	github.com/danielgtaylor/casing v0.0.0-20210126043903-4e55e6373ac3 // indirect
	github.com/danielgtaylor/mexpr v1.8.0 // indirect
	github.com/danielgtaylor/shorthand/v2 v2.1.1 // indirect
	github.com/fatih/color v1.15.0 // indirect
	github.com/fsnotify/fsnotify v1.6.0 // indirect
	github.com/fxamacker/cbor/v2 v2.5.0 // indirect
	github.com/goccy/go-yaml v1.11.0 // indirect
	github.com/google/uuid v1.3.1 // indirect
	github.com/hashicorp/hcl v1.0.0 // indirect
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
	github.com/magiconair/properties v1.8.7 // indirect
	github.com/mattn/go-colorable v0.1.13 // indirect
	github.com/mattn/go-isatty v0.0.20 // indirect
	github.com/mitchellh/mapstructure v1.5.0 // indirect
	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
	github.com/spf13/afero v1.9.5 // indirect
	github.com/spf13/cast v1.5.1 // indirect
	github.com/spf13/cobra v1.8.0 // indirect
	github.com/spf13/jwalterweatherman v1.1.0 // indirect
	github.com/spf13/pflag v1.0.5 // indirect
	github.com/spf13/viper v1.15.0 // indirect
	github.com/subosito/gotenv v1.4.2 // indirect
	github.com/x448/float16 v0.8.4 // indirect
	golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
	golang.org/x/net v0.19.0 // indirect
	golang.org/x/sys v0.15.0 // indirect
	golang.org/x/text v0.14.0 // indirect
	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
	gopkg.in/ini.v1 v1.67.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
)

vs. after this PR:

module example.com/demo

go 1.22

require github.com/danielgtaylor/huma/v2 v2.3.0

require (
	github.com/danielgtaylor/casing v1.0.0 // indirect
	github.com/fxamacker/cbor/v2 v2.5.0 // indirect
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
	github.com/spf13/cobra v1.8.0 // indirect
	github.com/spf13/pflag v1.0.5 // indirect
	github.com/x448/float16 v0.8.4 // indirect
)

So, what's left?

  • cbor & float16 are used to marshal/unmarshal a binary JSON format in the default service config. About 900kb.
  • cobra, pflag, and mousetrap are used for service CLI commands. About 1250kb.
  • casing is used for naming schemas & command options. About 30kb.

That leaves about 2mb of source to pull down, which could maybe be improved further. Unfortunately Cobra is part of the API contract, so removing it would be difficult/breaking. CBOR is in the default config so removing that would be hard and probably isn't desired anyway, and embedding casing doesn't save much (if anything). By comparison removing golang.org/x/text@v0.14.0 saved 40mb!

Lastly, this slightly improves both the build time and resulting executable size. Using the huma.rocks "Sending data" tutorial code on my M1 pro using gotip it goes from taking around 4.7s to compile+link to 4.1s (~12% improvement) and the resulting executable size goes from 14mb to 11mb (~20% improvement).

Edit: Huma is also now small & fast enough to use in the Go playground where previously it would always cause a timeout. Example using this PR branch to validate some input JSON against a schema: https://go.dev/play/p/OPTg-b5b8zH

@codecov
Copy link

codecov bot commented Feb 1, 2024

Codecov Report

Attention: 7 lines in your changes are missing coverage. Please review.

Comparison is base (9570636) 93.37% compared to head (406d748) 94.39%.

❗ Current head 406d748 differs from pull request most recent head 7172a41. Consider uploading reports for the commit 7172a41 to get more accurate results

Files Patch % Lines
openapi.go 96.44% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #223      +/-   ##
==========================================
+ Coverage   93.37%   94.39%   +1.02%     
==========================================
  Files          17       18       +1     
  Lines        2189     2606     +417     
==========================================
+ Hits         2044     2460     +416     
- Misses        106      107       +1     
  Partials       39       39              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@danielgtaylor danielgtaylor merged commit 11b18b0 into main Feb 2, 2024
@danielgtaylor danielgtaylor deleted the reduce-deps branch February 2, 2024 21:58
@ddl-ebrown
Copy link
Contributor

Awesome! This was my primary concern about using huma in production -- managing deps / security exposure / etc is a big deal, and a lot of scanners / tooling aren't smart enough to understand when a source code ref isn't actually compiled into the final binary.

Thanks a ton for working so hard on this!

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