{"id":20762516,"url":"https://github.com/welllog/golt","last_synced_at":"2025-07-27T21:36:13.047Z","repository":{"id":214036018,"uuid":"731933858","full_name":"welllog/golt","owner":"welllog","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-18T03:35:24.000Z","size":34,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-18T05:42:45.274Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/welllog.png","metadata":{"files":{"readme":"README-CN.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-15T08:23:57.000Z","updated_at":"2024-01-08T08:57:05.000Z","dependencies_parsed_at":"2023-12-25T10:44:27.678Z","dependency_job_id":"2bd01818-65f3-4514-968f-3b8ba955e589","html_url":"https://github.com/welllog/golt","commit_stats":null,"previous_names":["welllog/golt"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welllog%2Fgolt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welllog%2Fgolt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welllog%2Fgolt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welllog%2Fgolt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/welllog","download_url":"https://codeload.github.com/welllog/golt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243079567,"owners_count":20233009,"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":[],"created_at":"2024-11-17T10:35:41.696Z","updated_at":"2025-07-27T21:36:13.029Z","avatar_url":"https://github.com/welllog.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cbr\u003e \u003ca href=\"README.md\"\u003eEnglish\u003c/a\u003e | 中文\n\u003c/p\u003e\n\n# golt\n一个简单的http api开发工具库，尝试做到区别于Go标准http库的开发方式，在api开发上更简洁、易用\n\n### srvhttp库\n#### http handler\nGo http标准库及其它常用库\n```\nhttp.HandleFunc(\"/hello\", func(w http.ResponseWriter, r *http.Request) {\n    json.NewEncoder(w).Encode(map[string]string{\"hello\": \"world\"})\n})\n```\ngolt\n```\nengine := srvhttp.New()\nengine.Any(\"/hello\", func(ctx *srvhttp.Context) (any, error) {\n    return map[string]string{\"hello\": \"world\"}, nil\n})\n// Output:\n// {\"data\":{\"hello\":\"world\"}}\n\nengine.POST(\"/error\", func(ctx *Context) (any, error) {\n    return nil, unierr.New(1000, \"test error\").WithData(map[string]int{\"reason\": 20})\n})\n// Output:\n// {\"code\":1000,\"msg\":\"test error\",\"data\":{\"reason\":20}}\n```\n#### http middleware\n常见http路由中间件\n```\nmiddleware.Use(func(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {\n        next.ServeHTTP(writer, request)\n    })\n})\n```\ngolt\n```\nengine.Use(func(ctx *srvhttp.Context, next srvhttp.Handler) (any, error) {\n    ret, err := next(ctx)\n    if err != nil {\n        // todo\n    }\n    return ret, nil\n})\n```\n\n### srvhttp 使用概览\n```\n// 初始化一个http engine\nengine := srvhttp.New()\n\n// 添加路由\nuser := engine.Group(\"/user\")\nuser.POST(\"/login\", loginHandler)\nuser.PATCH(\"/info\", infoHandler)\nuser.Use(authMiddleware)\n\nengine.GET(\"/index\", indexHandler)\nengine.Sub().GET(\"/index/menu\", menuhandler)\nengine.Sub().GET(\"/index/articles/{category}/{id:[0-9]+}\", articleHandler)\nengine.Static(\"/static\", \"./static\", false)\n\n// 跨域\nengine.UseCors(srvhttp.CorsConfig{\n    AllowPrivateNetwork: true,\n    AllowCredentials:    true,\n    AllowOrigins:        []string{\"*127.0.0.1\", \"https://172.10.0.4\"},\n    AllowMethods:        []string{\"*\"},\n    AllowHeaders:        []string{\"*\"},\n    MaxAge:              12 * time.Hour,\n})\n\nsrv := http.Server{\n    Addr:    \"0.0.0.0:8080\",\n    Handler: engine,\n}\n\nsrv.ListenAndServe()\n```\n\n自定义响应处理函数\n```\nengine := srvhttp.New(\n    srvhttp.WithResponseFunc(func(response any, err error, c *srvhttp.Context) {\n        if err != nil {\n            c.WriteHeader(http.StatusBadRequest)\n            c.Write([]byte(err.Error()))\n            return\n        }\n        json.NewEncoder(c).Encode(response)\n    }),\n)\n```\n\n如果在http handler中需要返回特定数据而不使用通用响应函数，可以像使用http.ResponseWriter一样直接使用srvhttp.Context\n```\nengine.Any(\"/hello\", func(ctx *srvhttp.Context) (any, error) {\n    ctx.WriteHeader(http.StatusOK)\n    ctx.Write([]byte(\"hello world\"))\n    // 返回值会被中间件捕捉，如果此处返回nil,则后续中间件将拿不到结果\n    return nil, nil\n})\n\nengine.Any(\"/page\", func(ctx *srvhttp.Context) (any, error) {\n    ctx.WriteHeader(http.StatusOK)\n    ctx.Write([]byte(\"\u003chtml\u003e\u003cbody\u003e\u003ch1\u003ehello world\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e\"))\n    // 此处返回的值将不再出现在响应结果中，返回的错误同理,但仍会被中间获取到\n    return \"ok\", nil\n})\n```\n\n### config 库\ngolt的config库提供了统一的配置管理，支持从文件、etcd加载配置，支持动态加载配置，支持配置更新通知。\n其读取源需要一个额外的文件配置，config.FromFile(\"config.yaml\"),其中config.yaml中指定了读取配置的源以及映射方式\n\n#### 从文件加载配置\n从文件读取配置的\n```yaml\n  # 加载配置的源为文件系统\n  - source: file://\n    configs:\n      # 命名空间，决定了该配置从哪个文件中读取\n      - namespace: test/demo1 | test/demo2\n        # 命名空间指向的文件\n        path: test1.yaml\n        # 是否监听该文件变动来动态加载配置\n        dynamic: true\n```\n#### 从etcd加载配置\n```yaml\n  # 加载配置的源为etcd以及地址\n  - source: etcd://127.0.0.1:2379\n    configs:\n      # 命名空间，决定了该配置从哪个etcd及其key path中读取\n      - namespace: test/demo4\n        # 当前etcd下的key path\n        path: /v1/test/demo4/\n        # 是否监听该key path变动来动态加载配置\n        dynamic: true\n```\n#### 从自定义etcd客户端加载配置\n```yaml\n  # 加载配置的源为自定义etcd客户端\n  - source: custom_etcd://\n    configs:\n      # 命名空间，决定了该配置从哪个etcd及其key path中读取\n      - namespace: test/demo4\n        # 当前etcd下的key path\n        path: /v1/test/demo4/\n        # 是否监听该key path变动来动态加载配置\n        dynamic: true\n```\n#### config使用概览\n```\nc, err := FromFile(\"./config.yaml\") \nif err != nil {\n    panic(err)\n}\ndefer c.Close()\n\nc.String(\"test/demo1\", \"app_name\")\nc.Int64(\"test/demo2\", \"retry\")\nc.Int(\"test/demo2\", \"retry\")\nc.Float64(\"test/demo4\", \"rate\")\nc.Bool(\"test/demo4\", \"enable\")\nc.YamlDecode(\"test/demo1\", \"log\", \u0026logConf)\nc.JsonDecode(\"test/demo4\", \"data\", \u0026data)\nc.Decode(\"test/demo4\", \"data\", \u0026data, json.Unmarshal)\n\nc.GetRaw(\"test/demo1\", \"app_name\")\nc.UnsafeGetRaw(\"test/demo1\", \"app_name\")\nc.GetRawString(\"test/demo1\", \"app_name\")\n\nc.OnKeyChange(\"test/demo1\", \"app_name\", func([]byte) error) {\n    // do something\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwelllog%2Fgolt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwelllog%2Fgolt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwelllog%2Fgolt/lists"}