Package htadaptor
provides convenient generic domain logic adaptors for HTTP handlers. It eliminates boiler plate code, increases security by enforcing read limits and struct validation, and reduces bugs by providing a more intuitive request data parsing API than the standard library.
An HTTP request contains at least five various sources of input that your HTTP handlers may consider: URL path, URL query, headers, cookies, and the request body. Much of the code that you have to write manually is wrestling those inputs into a struct. Willem Schots wrote an excellent explanation here. htadaptor
can do all of it for you:
myHandler := htadaptor.Must(htadaptor.NewUnaryFuncAdaptor(
// your domain function call
func(context.Context, *myInputStruct) (*myOutputStruct, error) {
// ... myInputStruct is passed in already validated
// ... the fields of myInputStruct will be populated with
// ... the contents of `request.Body` with overrides
// from sources below in their given order:
},
htadaptor.WithPathValues("slug"), // (1) URL routing path
htadaptor.WithQueryValues("search"), // (2) URL query
htadaptor.WithHeaderValues("accessToken"), // (3) header
htadaptor.WithCookieValues("sessionID"), // (4) cookie
htadaptor.WithSessionValues("role"), // (5) session
))
The adaptors address common function signatures of domain logic calls that operate on a request struct and return a response struct with contextual awareness all the way through the call stack including the slog.Logger
:
Struct Adaptor | Parameter Values | Return Values |
---|---|---|
UnaryFunc | context, inputStruct | any, error |
NullaryFunc | context | any, error |
VoidFunc | context, inputStruct | error |
String adaptors are best when only one request value is needed:
String Adaptor | Parameter Values | Return Values |
---|---|---|
UnaryStringFunc | context, string | any, error |
VoidStringFunc | context, string | error |
go get github.com/dkotik/htadaptor@latest
mux := http.NewServeMux()
mux.Handle("/api/v1/order", htadaptor.Must(
htadaptor.NewUnaryFuncAdaptor(myService.Order),
))
See examples folder for common project uses.
The order of extractors matters with the latter overriding the former. Request body is always processed first.
- Path
- Chi Path
- Query
- Header
- Cookie
- Session
- Request properties can also be included into deserialization:
extract.NewMethodExtractor
extract.NewHostExtractor
extract.NewRemoteAddressExtractor
extract.NewUserAgentExtractor
- Or, make your own by implementing Extractor interface.
The core idea was sparked in conversations with members of the Ardan Labs team. Package includes reflection schema decoder from Gorilla toolkit. Similar projects:
- danielgtaylor/huma with REST and RPC
- dolanor/rip with REST
- go-fuego/fuego with OpenAPI
- matt1484/chimera for Chi
- calvinmclean/babyapi
How is htadaptor
different from the other generic HTTP adaptors? It is more terse due to focusing on wrapping http.Handlers
from the standard library. It is expected that the REST interface will be handled separately by either an http.Mux
or a helper.