{"id":13753521,"url":"https://github.com/lonng/nex","last_synced_at":"2025-07-10T08:35:22.034Z","repository":{"id":57484727,"uuid":"67966017","full_name":"lonng/nex","owner":"lonng","description":"Aiming to simplify the construction of JSON API service","archived":false,"fork":false,"pushed_at":"2017-09-15T14:51:59.000Z","size":31,"stargazers_count":34,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-13T21:40:45.020Z","etag":null,"topics":["dependency-injection","golang","handler","http","microservice","middleware","webservice"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lonng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-12T01:45:29.000Z","updated_at":"2022-02-17T04:00:23.000Z","dependencies_parsed_at":"2022-08-26T11:10:23.520Z","dependency_job_id":null,"html_url":"https://github.com/lonng/nex","commit_stats":null,"previous_names":["chrislonng/nex","lonnng/nex"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/lonng/nex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonng%2Fnex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonng%2Fnex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonng%2Fnex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonng%2Fnex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lonng","download_url":"https://codeload.github.com/lonng/nex/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonng%2Fnex/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264551669,"owners_count":23626536,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","golang","handler","http","microservice","middleware","webservice"],"created_at":"2024-08-03T09:01:23.832Z","updated_at":"2025-07-10T08:35:22.010Z","avatar_url":"https://github.com/lonng.png","language":"Go","readme":"# nex\r\nThis library aims to simplify the construction of JSON API service,\r\n`nex.Handler` is able to wrap any function to adapt the interface of\r\n`http.Handler`, which unmarshals POST data to a struct automatically.\r\n\r\n## Demo\r\n[中文示例](https://github.com/lonnng/yue)\r\n\r\n## Benchmark\r\n```\r\nBenchmarkSimplePlainAdapter_Invoke-8             5000000               318 ns/op              80 B/op          2 allocs/op\r\nBenchmarkSimpleUnaryAdapter_Invoke-8             1000000              1999 ns/op            1296 B/op         16 allocs/op\r\nBenchmarkGenericAdapter_Invoke-8                  500000              2404 ns/op            1456 B/op         17 allocs/op\r\nBenchmarkSimplePlainAdapter_Invoke2-8            1000000              1724 ns/op            1096 B/op         11 allocs/op\r\nBenchmarkSimpleUnaryAdapter_Invoke2-8             500000              3484 ns/op            2313 B/op         25 allocs/op\r\nBenchmarkGenericAdapter_Invoke2-8                 500000              3597 ns/op            2473 B/op         26 allocs/op\r\n```\r\n\r\n## Support types\r\n```\r\nio.ReadCloser      // request.Body\r\nhttp.Header        // request.Header\r\nnex.Form           // request.Form\r\nnex.PostForm       // request.PostForm\r\n*nex.Form          // request.Form\r\n*nex.PostForm      // request.PostForm\r\n*url.URL           // request.URL\r\n*multipart.Form    // request.MultipartForm\r\n*http.Request      // raw request\r\n```\r\n\r\n## Usage\r\n```\r\nhttp.Handle(\"/test\", nex.Handler(test))\r\n\r\nfunc test(io.ReadCloser, http.Header, nex.Form, nex.PostForm, *CustomizedRequestType, *url.URL, *multipart.Form) (*CustomizedResponseType, error)\r\n```\r\n\r\n## Example\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"errors\"\r\n\t\"fmt\"\r\n\t\"io\"\r\n\t\"net/http\"\r\n\t\"net/url\"\r\n\r\n\t\"github.com/lonnng/nex\"\r\n)\r\n\r\ntype LoginRequest struct {\r\n\tUsername string `json:\"username\"`\r\n\tPassword string `json:\"password\"`\r\n}\r\n\r\ntype LoginResponse struct {\r\n\tResult string `json:\"result\"`\r\n}\r\n\r\ntype ErrorMessage struct {\r\n\tCode  int    `json:\"code\"`\r\n\tError string `json:\"error\"`\r\n}\r\n\r\nfunc main() {\r\n\t// customize error encoder\r\n\tnex.SetErrorEncoder(func(err error) interface{} {\r\n\t\treturn \u0026ErrorMessage{Code: -1, Error: err.Error()}\r\n\t})\r\n\r\n\t// global middleware\r\n\tnex.Before(before1, before2)\r\n\tnex.After(after1, after2)\r\n\r\n\tmux := http.NewServeMux()\r\n\tmux.Handle(\"/test1\", nex.Handler(test1))\r\n\tmux.Handle(\"/test2\", nex.Handler(test2))\r\n\tmux.Handle(\"/test3\", nex.Handler(test3))\r\n\tmux.Handle(\"/test4\", nex.Handler(test4))\r\n\tmux.Handle(\"/test5\", nex.Handler(test5))\r\n\tmux.Handle(\"/test6\", nex.Handler(test6))\r\n\tmux.Handle(\"/test7\", nex.Handler(test7))\r\n\tmux.Handle(\"/test8\", nex.Handler(test8))\r\n\t// add middleware\r\n\tmux.Handle(\"/test9\", nex.Handler(test8).Before(before1, before2).After(after1, after2))\r\n\r\n\tlogic := func(ctx context.Context) (context.Context, *testResponse, error) {\r\n\t\tprintln(ctx.Value(\"key\").(string))\r\n\t\tprintln(ctx.Value(\"key2\").(string))\r\n\t\treturn context.WithValue(ctx, \"logic\", \"logic-value\"), \u0026testResponse{}, nil\r\n\t}\r\n\r\n\tbefore1 := func(ctx context.Context, request *http.Request) (context.Context, error) {\r\n\t\treturn context.WithValue(ctx, \"key\", \"value\"), nil\r\n\t}\r\n\r\n\tbefore2 := func(ctx context.Context, request *http.Request) (context.Context, error) {\r\n\t\tprintln(ctx.Value(\"key\").(string))\r\n\t\treturn context.WithValue(ctx, \"key2\", \"value2\"), nil\r\n\t}\r\n\r\n\tafter1 := func(ctx context.Context, w http.ResponseWriter) (context.Context, error) {\r\n\t\tprintln(ctx.Value(\"key\").(string))\r\n\t\tprintln(ctx.Value(\"key2\").(string))\r\n\t\tprintln(ctx.Value(\"logic\").(string))\r\n\r\n\t\treturn context.WithValue(ctx, \"after1\", \"after1-value\"), nil\r\n\t}\r\n\r\n\tafter2 := func(ctx context.Context, w http.ResponseWriter) (context.Context, error) {\r\n\t\tprintln(ctx.Value(\"key\").(string))\r\n\t\tprintln(ctx.Value(\"key2\").(string))\r\n\t\tprintln(ctx.Value(\"logic\").(string))\r\n\t\tprintln(ctx.Value(\"after1\").(string))\r\n\r\n\t\treturn context.WithValue(ctx, \"key\", \"value\"), nil\r\n\t}\r\n\r\n\thandler := Handler(logic).Before(before1, before2).After(after1, after2)\r\n\r\n\tmux.Handle(\"/context\", handler)\r\n\r\n\thttp.ListenAndServe(\":8080\", mux)\r\n}\r\n\r\n// POST: regular response\r\nfunc test1(m *LoginRequest) (*LoginResponse, error) {\r\n\tfmt.Printf(\"%+v\\n\", m)\r\n\treturn \u0026LoginResponse{Result: \"success\"}, nil\r\n}\r\n\r\n// POST: error response\r\nfunc test2(m *LoginRequest) (*LoginResponse, error) {\r\n\tfmt.Printf(\"%+v\\n\", m)\r\n\treturn nil, errors.New(\"error test\")\r\n}\r\n\r\n// GET: regular response\r\nfunc test3() (*LoginResponse, error) {\r\n\treturn \u0026LoginResponse{Result: \"success\"}, nil\r\n}\r\n\r\n// GET: error response\r\nfunc test4() (*LoginResponse, error) {\r\n\treturn nil, errors.New(\"error test\")\r\n}\r\n\r\nfunc test5(header http.Header) (*LoginResponse, error) {\r\n\tfmt.Printf(\"%#v\\n\", header)\r\n\treturn \u0026LoginResponse{Result: \"success\"}, nil\r\n}\r\n\r\nfunc test6(form nex.Form) (*LoginResponse, error) {\r\n\tfmt.Printf(\"%#v\\n\", form)\r\n\t// use form helper method\r\n\t// start := query.IntOrDefault(\"start\", 0)\r\n\t// count := query.IntOrDefault(\"count\", -1)\r\n\treturn \u0026LoginResponse{Result: \"success\"}, nil\r\n}\r\n\r\nfunc test7(header http.Header, form nex.Form, body io.ReadCloser) (*LoginResponse, error) {\r\n\tfmt.Printf(\"%#v\\n\", header)\r\n\tfmt.Printf(\"%#v\\n\", form)\r\n\treturn \u0026LoginResponse{Result: \"success\"}, nil\r\n}\r\n\r\nfunc test8(header http.Header, r *LoginResponse, url *url.URL) (*LoginResponse, error) {\r\n\tfmt.Printf(\"%#v\\n\", header)\r\n\tfmt.Printf(\"%#v\\n\", r)\r\n\tfmt.Printf(\"%#v\\n\", url)\r\n\treturn \u0026LoginResponse{Result: \"success\"}, nil\r\n}\r\n```\r\n\r\n```\r\ncurl -XPOST -d '{\"username\":\"test\", \"password\":\"test\"}' http://localhost:8080/test1\r\ncurl -XPOST -d '{\"username\":\"test\", \"password\":\"test\"}' http://localhost:8080/test2\r\ncurl  http://localhost:8080/test3\r\ncurl  http://localhost:8080/test4\r\ncurl  http://localhost:8080/test5\r\ncurl  http://localhost:8080/test6\\?test\\=test\r\ncurl  http://localhost:8080/test7\\?test\\=tset\r\ncurl -XPOST -d '{\"username\":\"test\", \"password\":\"test\"}' http://localhost:8080/test8\\?test\\=test\r\n```\r\n\r\n## License\r\nCopyright (c) \u003c2016\u003e \u003cchris@lonng.org\u003e\r\n\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of \r\nthis software and associated documentation files (the \"Software\"), to deal in \r\nthe Software without restriction, including without limitation the rights to use, \r\ncopy, modify, merge, publish, distribute, sublicense, and/or sell copies of the \r\nSoftware, and to permit persons to whom the Software is furnished to do so, subject \r\nto the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all \r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, \r\nINCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A \r\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT \r\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION \r\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE \r\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n","funding_links":[],"categories":["webservice"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flonng%2Fnex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flonng%2Fnex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flonng%2Fnex/lists"}