{"id":23588117,"url":"https://github.com/sonirico/withttp","last_synced_at":"2025-08-13T15:44:19.975Z","repository":{"id":58139569,"uuid":"525146778","full_name":"sonirico/withttp","owner":"sonirico","description":"go build http 🌐 requests with fluency and wit ✨","archived":false,"fork":false,"pushed_at":"2023-02-15T19:33:41.000Z","size":109,"stargazers_count":19,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-31T09:04:39.048Z","etag":null,"topics":["builder","fluent-api","generics","golang","golang-library","hacktoberfest","http","http-client","http-requests","https"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sonirico.png","metadata":{"files":{"readme":"README.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":"2022-08-15T21:40:35.000Z","updated_at":"2022-12-27T23:53:03.000Z","dependencies_parsed_at":"2024-12-27T07:01:16.051Z","dependency_job_id":null,"html_url":"https://github.com/sonirico/withttp","commit_stats":{"total_commits":25,"total_committers":3,"mean_commits":8.333333333333334,"dds":"0.31999999999999995","last_synced_commit":"164627b24e6e61f4a49ff3d0a2bc01303aa619a3"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonirico%2Fwithttp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonirico%2Fwithttp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonirico%2Fwithttp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonirico%2Fwithttp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sonirico","download_url":"https://codeload.github.com/sonirico/withttp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252860321,"owners_count":21815497,"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":["builder","fluent-api","generics","golang","golang-library","hacktoberfest","http","http-client","http-requests","https"],"created_at":"2024-12-27T05:12:28.084Z","updated_at":"2025-08-13T15:44:19.954Z","avatar_url":"https://github.com/sonirico.png","language":"Go","readme":"\u003cdiv align=\"center\"\u003e\n\n# 🎯 withttp\n\n**Build HTTP requests and parse responses with fluent syntax and wit**\n\n[![Build Status](https://github.com/sonirico/withttp/actions/workflows/go.yml/badge.svg)](https://github.com/sonirico/withttp/actions/workflows/go.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/sonirico/withttp)](https://goreportcard.com/report/github.com/sonirico/withttp)\n[![GoDoc](https://godoc.org/github.com/sonirico/withttp?status.svg)](https://godoc.org/github.com/sonirico/withttp)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Go Version](https://img.shields.io/badge/go-1.23+-blue.svg)](https://golang.org/dl/)\n\n*A fluent HTTP client library that covers common scenarios while maintaining maximum flexibility*\n\n\u003c/div\u003e\n\n---\n\n## 🚀 Features\n\n- **🔄 Fluent API** - Chain methods for intuitive request building\n- **📡 Multiple HTTP Backends** - Support for `net/http` and `fasthttp`\n- **🎯 Type-Safe Responses** - Generic-based response parsing\n- **📊 Streaming Support** - Stream data from slices, channels, or readers\n- **🧪 Mock-Friendly** - Built-in mocking capabilities for testing\n- **⚡ High Performance** - Optimized for speed and low allocations\n\n## 📦 Installation\n\n```bash\ngo get github.com/sonirico/withttp\n```\n\n## 🎛️ Supported HTTP Implementations\n\n| Implementation                                             | Description                                                                                     |\n| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |\n| [net/http](https://pkg.go.dev/net/http)                    | Go's standard HTTP client                                                                       |\n| [fasthttp](https://pkg.go.dev/github.com/valyala/fasthttp) | High-performance HTTP client                                                                    |\n| Custom Client                                              | Implement the [Client interface](https://github.com/sonirico/withttp/blob/main/endpoint.go#L43) |\n\n\u003e 💡 Missing your preferred HTTP client? [Open an issue](https://github.com/sonirico/withttp/issues/new) and let us know!\n\n## 📚 Table of Contents\n\n- [🎯 withttp](#-withttp)\n  - [🚀 Features](#-features)\n  - [📦 Installation](#-installation)\n  - [🎛️ Supported HTTP Implementations](#️-supported-http-implementations)\n  - [📚 Table of Contents](#-table-of-contents)\n  - [🏁 Quick Start](#-quick-start)\n  - [💡 Examples](#-examples)\n    - [RESTful API Queries](#restful-api-queries)\n    - [Streaming Data](#streaming-data)\n      - [📄 Stream from Slice](#-stream-from-slice)\n      - [📡 Stream from Channel](#-stream-from-channel)\n      - [📖 Stream from Reader](#-stream-from-reader)\n    - [Multiple Endpoints](#multiple-endpoints)\n    - [Testing with Mocks](#testing-with-mocks)\n  - [🗺️ Roadmap](#️-roadmap)\n  - [🤝 Contributing](#-contributing)\n  - [📄 License](#-license)\n  - [⭐ Show Your Support](#-show-your-support)\n\n## 🏁 Quick Start\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"net/http\"\n    \n    \"github.com/sonirico/withttp\"\n)\n\ntype GithubRepo struct {\n    ID   int    `json:\"id\"`\n    Name string `json:\"name\"`\n    URL  string `json:\"html_url\"`\n}\n\nfunc main() {\n    call := withttp.NewCall[GithubRepo](withttp.Fasthttp()).\n        URL(\"https://api.github.com/repos/sonirico/withttp\").\n        Method(http.MethodGet).\n        Header(\"User-Agent\", \"withttp-example/1.0\", false).\n        ParseJSON().\n        ExpectedStatusCodes(http.StatusOK)\n\n    err := call.Call(context.Background())\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Printf(\"Repository: %s (ID: %d)\\n\", call.BodyParsed.Name, call.BodyParsed.ID)\n}\n```\n\n## 💡 Examples\n\nAll examples are now available as:\n- **Example functions** in the test files - you can run these with `go test -v -run \"^Example\"`\n- **Test functions** for comprehensive testing scenarios\n- **Documentation examples** in the code itself\n\n### RESTful API Queries\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand\u003c/summary\u003e\n\n```go\ntype GithubRepoInfo struct {\n  ID  int    `json:\"id\"`\n  URL string `json:\"html_url\"`\n}\n\nfunc GetRepoInfo(user, repo string) (GithubRepoInfo, error) {\n  call := withttp.NewCall[GithubRepoInfo](withttp.Fasthttp()).\n    URL(fmt.Sprintf(\"https://api.github.com/repos/%s/%s\", user, repo)).\n    Method(http.MethodGet).\n    Header(\"User-Agent\", \"withttp/0.5.1 See https://github.com/sonirico/withttp\", false).\n    ParseJSON().\n    ExpectedStatusCodes(http.StatusOK)\n\n  err := call.Call(context.Background())\n  return call.BodyParsed, err\n}\n\nfunc main() {\n  info, _ := GetRepoInfo(\"sonirico\", \"withttp\")\n  log.Println(info)\n}\n```\n\n\u003c/details\u003e\n\n### Streaming Data\n\n#### 📄 Stream from Slice\n\n\u003cdetails\u003e\n\u003csummary\u003eView example\u003c/summary\u003e\n\n[See test example](https://github.com/sonirico/withttp/blob/main/examples_request_stream_test.go)\n\n```go\ntype metric struct {\n  Time time.Time `json:\"t\"`\n  Temp float32   `json:\"T\"`\n}\n\nfunc CreateStream() error {\n  points := []metric{\n    {Time: time.Unix(time.Now().Unix()-1, 0), Temp: 39},\n    {Time: time.Now(), Temp: 40},\n  }\n\n  stream := withttp.Slice[metric](points)\n  testEndpoint := withttp.NewEndpoint(\"webhook-site-request-stream-example\").\n    Request(withttp.BaseURL(\"https://webhook.site/24e84e8f-75cf-4239-828e-8bed244c0afb\"))\n\n  call := withttp.NewCall[any](withttp.Fasthttp()).\n    Method(http.MethodPost).\n    ContentType(withttp.ContentTypeJSONEachRow).\n    RequestSniffed(func(data []byte, err error) {\n      fmt.Printf(\"recv: '%s', err: %v\", string(data), err)\n    }).\n    RequestStreamBody(withttp.RequestStreamBody[any, metric](stream)).\n    ExpectedStatusCodes(http.StatusOK)\n\n  return call.CallEndpoint(context.Background(), testEndpoint)\n}\n```\n\n\u003c/details\u003e\n\n#### 📡 Stream from Channel\n\n\u003cdetails\u003e\n\u003csummary\u003eView example\u003c/summary\u003e\n\n[See test example](https://github.com/sonirico/withttp/blob/main/examples_request_stream_test.go)\n\n```go\nfunc CreateStreamChannel() error {\n  points := make(chan metric, 2)\n\n  go func() {\n    points \u003c- metric{Time: time.Unix(time.Now().Unix()-1, 0), Temp: 39}\n    points \u003c- metric{Time: time.Now(), Temp: 40}\n    close(points)\n  }()\n\n  stream := withttp.Channel[metric](points)\n  testEndpoint := withttp.NewEndpoint(\"webhook-site-request-stream-example\").\n    Request(withttp.BaseURL(\"https://webhook.site/24e84e8f-75cf-4239-828e-8bed244c0afb\"))\n\n  call := withttp.NewCall[any](withttp.Fasthttp()).\n    Method(http.MethodPost).\n    ContentType(withttp.ContentTypeJSONEachRow).\n    RequestSniffed(func(data []byte, err error) {\n      fmt.Printf(\"recv: '%s', err: %v\", string(data), err)\n    }).\n    RequestStreamBody(withttp.RequestStreamBody[any, metric](stream)).\n    ExpectedStatusCodes(http.StatusOK)\n\n  return call.CallEndpoint(context.Background(), testEndpoint)\n}\n```\n\n\u003c/details\u003e\n\n#### 📖 Stream from Reader\n\n\u003cdetails\u003e\n\u003csummary\u003eView example\u003c/summary\u003e\n\n[See test example](https://github.com/sonirico/withttp/blob/main/examples_request_stream_test.go)\n\n```go\nfunc CreateStreamReader() error {\n  buf := bytes.NewBuffer(nil)\n\n  go func() {\n    buf.WriteString(\"{\\\"t\\\":\\\"2022-09-01T00:58:15+02:00\\\"\")\n    buf.WriteString(\",\\\"T\\\":39}\\n{\\\"t\\\":\\\"2022-09-01T00:59:15+02:00\\\",\\\"T\\\":40}\\n\")\n  }()\n\n  streamFactory := withttp.NewProxyStreamFactory(1 \u003c\u003c 10)\n  stream := withttp.NewStreamFromReader(buf, streamFactory)\n  testEndpoint := withttp.NewEndpoint(\"webhook-site-request-stream-example\").\n    Request(withttp.BaseURL(\"https://webhook.site/24e84e8f-75cf-4239-828e-8bed244c0afb\"))\n\n  call := withttp.NewCall[any](withttp.NetHttp()).\n    Method(http.MethodPost).\n    RequestSniffed(func(data []byte, err error) {\n      fmt.Printf(\"recv: '%s', err: %v\", string(data), err)\n    }).\n    ContentType(withttp.ContentTypeJSONEachRow).\n    RequestStreamBody(withttp.RequestStreamBody[any, []byte](stream)).\n    ExpectedStatusCodes(http.StatusOK)\n\n  return call.CallEndpoint(context.Background(), testEndpoint)\n}\n```\n\n\u003c/details\u003e\n\n### Multiple Endpoints\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand\u003c/summary\u003e\n\nDefine reusable endpoint configurations for API consistency:\n\n```go\nvar (\n  githubApi = withttp.NewEndpoint(\"GithubAPI\").\n    Request(withttp.BaseURL(\"https://api.github.com/\"))\n)\n\ntype GithubRepoInfo struct {\n  ID  int    `json:\"id\"`\n  URL string `json:\"html_url\"`\n}\n\nfunc GetRepoInfo(user, repo string) (GithubRepoInfo, error) {\n  call := withttp.NewCall[GithubRepoInfo](withttp.Fasthttp()).\n    URI(fmt.Sprintf(\"repos/%s/%s\", user, repo)).\n    Method(http.MethodGet).\n    Header(\"User-Agent\", \"withttp/0.5.1 See https://github.com/sonirico/withttp\", false).\n    HeaderFunc(func() (key, value string, override bool) {\n      return \"X-Date\", time.Now().String(), true\n    }).\n    ParseJSON().\n    ExpectedStatusCodes(http.StatusOK)\n\n  err := call.CallEndpoint(context.Background(), githubApi)\n  return call.BodyParsed, err\n}\n\ntype GithubCreateIssueResponse struct {\n  ID  int    `json:\"id\"`\n  URL string `json:\"url\"`\n}\n\nfunc CreateRepoIssue(user, repo, title, body, assignee string) (GithubCreateIssueResponse, error) {\n  type payload struct {\n    Title    string `json:\"title\"`\n    Body     string `json:\"body\"`\n    Assignee string `json:\"assignee\"`\n  }\n\n  p := payload{Title: title, Body: body, Assignee: assignee}\n\n  call := withttp.NewCall[GithubCreateIssueResponse](withttp.Fasthttp()).\n    URI(fmt.Sprintf(\"repos/%s/%s/issues\", user, repo)).\n    Method(http.MethodPost).\n    ContentType(\"application/vnd+github+json\").\n    Body(p).\n    HeaderFunc(func() (key, value string, override bool) {\n      return \"Authorization\", fmt.Sprintf(\"Bearer %s\", \"S3cret\"), true\n    }).\n    ExpectedStatusCodes(http.StatusCreated)\n\n  err := call.CallEndpoint(context.Background(), githubApi)\n  log.Println(\"req body\", string(call.Req.Body()))\n\n  return call.BodyParsed, err\n}\n\nfunc main() {\n  // Fetch repo info\n  info, _ := GetRepoInfo(\"sonirico\", \"withttp\")\n  log.Println(info)\n\n  // Create an issue\n  res, err := CreateRepoIssue(\"sonirico\", \"withttp\", \"test\", \"This is a test\", \"sonirico\")\n  log.Println(res, err)\n}\n```\n\n\u003c/details\u003e\n\n### Testing with Mocks\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand\u003c/summary\u003e\n\nEasily test your HTTP calls with built-in mocking:\n\n```go\nvar (\n  exchangeListOrders = withttp.NewEndpoint(\"ListOrders\").\n    Request(withttp.BaseURL(\"http://example.com\")).\n    Response(\n      withttp.MockedRes(func(res withttp.Response) {\n        res.SetBody(io.NopCloser(bytes.NewReader(mockResponse)))\n        res.SetStatus(http.StatusOK)\n      }),\n    )\n  mockResponse = []byte(strings.TrimSpace(`\n    {\"amount\": 234, \"pair\": \"BTC/USDT\"}\n    {\"amount\": 123, \"pair\": \"ETH/USDT\"}`))\n)\n\nfunc main() {\n  type Order struct {\n    Amount float64 `json:\"amount\"`\n    Pair   string  `json:\"pair\"`\n  }\n\n  res := make(chan Order)\n\n  call := withttp.NewCall[Order](withttp.Fasthttp()).\n    URL(\"https://github.com/\").\n    Method(http.MethodGet).\n    Header(\"User-Agent\", \"withttp/0.5.1 See https://github.com/sonirico/withttp\", false).\n    ParseJSONEachRowChan(res).\n    ExpectedStatusCodes(http.StatusOK)\n\n  go func() {\n    for order := range res {\n      log.Println(order)\n    }\n  }()\n\n  err := call.CallEndpoint(context.Background(), exchangeListOrders)\n  if err != nil {\n    panic(err)\n  }\n}\n```\n\n\u003c/details\u003e\n\n## 🗺️ Roadmap\n\n| Feature                       | Status        |\n| ----------------------------- | ------------- |\n| Form-data content type codecs | 🔄 In Progress |\n| Enhanced auth methods         | 📋 Planned     |\n| XML parsing support           | 📋 Planned     |\n| Tabular data support          | 📋 Planned     |\n| gRPC integration              | 🤔 Considering |\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## ⭐ Show Your Support\n\nIf this project helped you, please give it a ⭐! It helps others discover the project.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**[Documentation](https://godoc.org/github.com/sonirico/withttp)** • \n**[Test Examples](https://github.com/sonirico/withttp/blob/main/)** • \n**[Issues](https://github.com/sonirico/withttp/issues)** • \n**[Discussions](https://github.com/sonirico/withttp/discussions)**\n\nMade with ❤️ by [sonirico](https://github.com/sonirico)\n\n\u003c/div\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsonirico%2Fwithttp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsonirico%2Fwithttp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsonirico%2Fwithttp/lists"}