diff --git a/README.md b/README.md index ca66605..2886b0f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # community-examples + go-chi community examples + +- [httpin](./httpin/): decode an HTTP request into a custom struct, including querystring, headers, form-data, JSON/XML body, path variables, etc. diff --git a/httpin/README.md b/httpin/README.md new file mode 100644 index 0000000..764035d --- /dev/null +++ b/httpin/README.md @@ -0,0 +1,19 @@ +# httpin + +**httpin** - Decode an HTTP request into a custom struct, including querystring, forms, HTTP headers, etc. + +Documentation: https://ggicci.github.io/httpin/ + +Integrate with chi: https://ggicci.github.io/httpin/integrations/gochi. + +## Run this example + +```bash +# start the http server +go run main.go + + +curl -H "Authorization: abc" "http://localhost:3333/users/ggicci/repos?visibility=private&fork=1" +# Output: +# {"Username":"ggicci","Visibility":"private","Fork":true,"Token":"abc"} +``` diff --git a/httpin/go.mod b/httpin/go.mod new file mode 100644 index 0000000..573d75f --- /dev/null +++ b/httpin/go.mod @@ -0,0 +1,8 @@ +module httpin + +go 1.19 + +require ( + github.com/ggicci/httpin v0.10.1 + github.com/go-chi/chi/v5 v5.0.7 +) diff --git a/httpin/go.sum b/httpin/go.sum new file mode 100644 index 0000000..9a938f2 --- /dev/null +++ b/httpin/go.sum @@ -0,0 +1,21 @@ +github.com/ggicci/httpin v0.10.1 h1:qLHjEBjn/ErbUHFryeXYb6ZJtbt4B9dCAVd+Bl8GaxM= +github.com/ggicci/httpin v0.10.1/go.mod h1:RpidMNiWsPdLRwjuXAcvguOOWsEv0KS/ekjTp53UPqY= +github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= +github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= +github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/httpin/main.go b/httpin/main.go new file mode 100644 index 0000000..ad71f37 --- /dev/null +++ b/httpin/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "encoding/json" + "net/http" + + "github.com/ggicci/httpin" + "github.com/go-chi/chi/v5" +) + +type ListUserReposInput struct { + Username string `in:"path=username"` + Visibility string `in:"query=visibility"` + Fork bool `in:"query=fork"` + Token string `in:"header=Authorization"` +} + +func ListUserRepos(rw http.ResponseWriter, r *http.Request) { + // Retrieve you data in one line of code! + input := r.Context().Value(httpin.Input).(*ListUserReposInput) + + json.NewEncoder(rw).Encode(input) +} + +func init() { + // Register a directive named "path" to retrieve values from `chi.URLParam`, + // i.e. decode path variables. + httpin.UseGochiURLParam("path", chi.URLParam) +} + +func main() { + r := chi.NewRouter() + + // Bind input struct with handler. + r.With( + httpin.NewInput(ListUserReposInput{}), + ).Get("/users/{username}/repos", ListUserRepos) + + http.ListenAndServe(":3333", r) +}