{"id":13413657,"url":"https://github.com/earthboundkid/requests","last_synced_at":"2025-04-07T23:13:14.893Z","repository":{"id":37665694,"uuid":"369315012","full_name":"earthboundkid/requests","owner":"earthboundkid","description":"HTTP requests for Gophers","archived":false,"fork":false,"pushed_at":"2024-08-27T19:53:01.000Z","size":229,"stargazers_count":1495,"open_issues_count":2,"forks_count":52,"subscribers_count":15,"default_branch":"main","last_synced_at":"2024-10-29T15:43:28.584Z","etag":null,"topics":["convenience","golang","helper","http","http-client","requests"],"latest_commit_sha":null,"homepage":"https://blog.carlana.net/post/2021/requests-golang-http-client/","language":"Go","has_issues":false,"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/earthboundkid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"earthboundkid"}},"created_at":"2021-05-20T19:20:29.000Z","updated_at":"2024-10-29T01:09:25.000Z","dependencies_parsed_at":"2023-02-17T10:16:06.303Z","dependency_job_id":"82449db3-5509-4c1a-a8ec-9151af9c0d1c","html_url":"https://github.com/earthboundkid/requests","commit_stats":{"total_commits":233,"total_committers":8,"mean_commits":29.125,"dds":0.06008583690987124,"last_synced_commit":"9ab79a0c8b462518a3adac7c4ca21289eb2557f4"},"previous_names":["earthboundkid/requests","carlmjohnson/requests"],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthboundkid%2Frequests","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthboundkid%2Frequests/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthboundkid%2Frequests/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthboundkid%2Frequests/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/earthboundkid","download_url":"https://codeload.github.com/earthboundkid/requests/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247744335,"owners_count":20988783,"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":["convenience","golang","helper","http","http-client","requests"],"created_at":"2024-07-30T20:01:45.616Z","updated_at":"2025-04-07T23:13:14.865Z","avatar_url":"https://github.com/earthboundkid.png","language":"Go","readme":"# Requests [![GoDoc](https://godoc.org/github.com/carlmjohnson/requests?status.svg)](https://godoc.org/github.com/carlmjohnson/requests) [![Go Report Card](https://goreportcard.com/badge/github.com/carlmjohnson/requests)](https://goreportcard.com/report/github.com/carlmjohnson/requests) [![Coverage Status](https://coveralls.io/repos/github/earthboundkid/requests/badge.svg)](https://coveralls.io/github/earthboundkid/requests) [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)\n\n![Requests logo](https://github.com/earthboundkid/requests/assets/222245/e59a9f82-c6c7-46d8-96b2-ce2f7dd58dce)\n\n## _HTTP requests for Gophers._\n\n**The problem**: Go's net/http is powerful and versatile, but using it correctly for client requests can be extremely verbose.\n\n**The solution**: The requests.Builder type is a convenient way to build, send, and handle HTTP requests. Builder has a fluent API with methods returning a pointer to the same struct, which allows for declaratively describing a request by method chaining.\n\nRequests also comes with tools for building custom http transports, include a request recorder and replayer for testing.\n\n*[See this note on the canonical project URL.](https://gist.github.com/earthboundkid/8915002ae0e531cecdfc58bc6453ac80)*\n\n## Features\n\n- Simplifies HTTP client usage compared to net/http\n- Can't forget to close response body\n- Checks status codes by default\n- Supports context.Context\n- JSON serialization and deserialization helpers\n- Easily manipulate URLs and query parameters\n- Request recording and replaying for tests\n- Customizable transports and validators that are compatible with the standard library and third party libraries\n- No third party dependencies\n- Good test coverage\n\n## Examples\n### Simple GET into a string\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003cstrong\u003ecode with net/http\u003c/strong\u003e\u003c/th\u003e\n\u003cth\u003e\u003cstrong\u003ecode with requests\u003c/strong\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\nreq, err := http.NewRequestWithContext(ctx,\n\thttp.MethodGet, \"http://example.com\", nil)\nif err != nil {\n\t// ...\n}\nres, err := http.DefaultClient.Do(req)\nif err != nil {\n\t// ...\n}\ndefer res.Body.Close()\nb, err := io.ReadAll(res.Body)\nif err != nil {\n\t// ...\n}\ns := string(b)\n```\n\u003c/td\u003e\n\u003ctd\u003e\n\n```go\nvar s string\nerr := requests.\n\tURL(\"http://example.com\").\n\tToString(\u0026s).\n\tFetch(ctx)\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e11+ lines\u003c/td\u003e\u003ctd\u003e5 lines\u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n### POST a raw body\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003cstrong\u003ecode with net/http\u003c/strong\u003e\u003c/th\u003e\n\u003cth\u003e\u003cstrong\u003ecode with requests\u003c/strong\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\nbody := bytes.NewReader(([]byte(`hello, world`))\nreq, err := http.NewRequestWithContext(ctx, http.MethodPost,\n\t\"https://postman-echo.com/post\", body)\nif err != nil {\n\t// ...\n}\nreq.Header.Set(\"Content-Type\", \"text/plain\")\nres, err := http.DefaultClient.Do(req)\nif err != nil {\n\t// ...\n}\ndefer res.Body.Close()\n_, err := io.ReadAll(res.Body)\nif err != nil {\n\t// ...\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```go\nerr := requests.\n\tURL(\"https://postman-echo.com/post\").\n\tBodyBytes([]byte(`hello, world`)).\n\tContentType(\"text/plain\").\n\tFetch(ctx)\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e12+ lines\u003c/td\u003e\u003ctd\u003e5 lines\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\n\n### GET a JSON object\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003cstrong\u003ecode with net/http\u003c/strong\u003e\u003c/th\u003e\n\u003cth\u003e\u003cstrong\u003ecode with requests\u003c/strong\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\nvar post placeholder\nu, err := url.Parse(\"https://jsonplaceholder.typicode.com\")\nif err != nil {\n\t// ...\n}\nu.Path = fmt.Sprintf(\"/posts/%d\", 1)\nreq, err := http.NewRequestWithContext(ctx,\n\thttp.MethodGet, u.String(), nil)\nif err != nil {\n\t// ...\n}\nres, err := http.DefaultClient.Do(req)\nif err != nil {\n\t// ...\n}\ndefer res.Body.Close()\nb, err := io.ReadAll(res.Body)\nif err != nil {\n\t// ...\n}\nerr := json.Unmarshal(b, \u0026post)\nif err != nil {\n\t// ...\n}\n```\n\u003c/td\u003e\u003ctd\u003e\n\n```go\nvar post placeholder\nerr := requests.\n\tURL(\"https://jsonplaceholder.typicode.com\").\n\tPathf(\"/posts/%d\", 1).\n\tToJSON(\u0026post).\n\tFetch(ctx)\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e18+ lines\u003c/td\u003e\u003ctd\u003e7 lines\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\n\n### POST a JSON object and parse the response\n\n```go\nvar res placeholder\nreq := placeholder{\n\tTitle:  \"foo\",\n\tBody:   \"baz\",\n\tUserID: 1,\n}\nerr := requests.\n\tURL(\"/posts\").\n\tHost(\"jsonplaceholder.typicode.com\").\n\tBodyJSON(\u0026req).\n\tToJSON(\u0026res).\n\tFetch(ctx)\n// net/http equivalent left as an exercise for the reader\n```\n\n### Set custom headers for a request\n\n```go\n// Set headers\nvar headers postman\nerr := requests.\n\tURL(\"https://postman-echo.com/get\").\n\tUserAgent(\"bond/james-bond\").\n\tContentType(\"secret\").\n\tHeader(\"martini\", \"shaken\").\n\tFetch(ctx)\n```\n\n### Easily manipulate URLs and query parameters\n\n```go\nu, err := requests.\n\tURL(\"https://prod.example.com/get?a=1\u0026b=2\").\n\tHostf(\"%s.example.com\", \"dev1\").\n\tParam(\"b\", \"3\").\n\tParamInt(\"c\", 4).\n\tURL()\nif err != nil { /* ... */ }\nfmt.Println(u.String()) // https://dev1.example.com/get?a=1\u0026b=3\u0026c=4\n```\n\n### Record and replay responses\n\n```go\n// record a request to the file system\nvar s1, s2 string\nerr := requests.URL(\"http://example.com\").\n\tTransport(reqtest.Record(nil, \"somedir\")).\n\tToString(\u0026s1).\n\tFetch(ctx)\ncheck(err)\n\n// now replay the request in tests\nerr = requests.URL(\"http://example.com\").\n\tTransport(reqtest.Replay(\"somedir\")).\n\tToString(\u0026s2).\n\tFetch(ctx)\ncheck(err)\nassert(s1 == s2) // true\n```\n\n## FAQs\n\n[See wiki](https://github.com/earthboundkid/requests/wiki) for more details.\n\n### Why not just use the standard library HTTP client?\n\nBrad Fitzpatrick, long time maintainer of the net/http package, [wrote an extensive list of problems with the standard library HTTP client](https://github.com/bradfitz/exp-httpclient/blob/master/problems.md). His four main points (ignoring issues that can't be resolved by a wrapper around the standard library) are:\n\n\u003e - Too easy to not call Response.Body.Close.\n\u003e - Too easy to not check return status codes\n\u003e - Context support is oddly bolted on\n\u003e - Proper usage is too many lines of boilerplate\n\nRequests solves these issues by always closing the response body, checking status codes by default, always requiring a `context.Context`, and simplifying the boilerplate with a descriptive UI based on fluent method chaining.\n\n### Why requests and not some other helper library?\n\nThere are two major flaws in other libraries as I see it. One is that in other libraries support for `context.Context` tends to be bolted on if it exists at all. Two, many hide the underlying `http.Client` in such a way that it is difficult or impossible to replace or mock out. Beyond that, I believe that none have achieved the same core simplicity that the requests library has.\n\n### How do I just get some JSON?\n\n```go\nvar data SomeDataType\nerr := requests.\n\tURL(\"https://example.com/my-json\").\n\tToJSON(\u0026data).\n\tFetch(ctx)\n```\n\n### How do I post JSON and read the response JSON?\n\n```go\nbody := MyRequestType{}\nvar resp MyResponseType\nerr := requests.\n\tURL(\"https://example.com/my-json\").\n\tBodyJSON(\u0026body).\n\tToJSON(\u0026resp).\n\tFetch(ctx)\n```\n\n### How do I just save a file to disk?\n\nIt depends on exactly what you need in terms of file atomicity and buffering, but this will work for most cases:\n\n```go\nerr := requests.\n\tURL(\"http://example.com\").\n\tToFile(\"myfile.txt\").\n\tFetch(ctx)\n```\n\nFor more advanced use case, use `ToWriter`.\n\n### How do I save a response to a string?\n\n```go\nvar s string\nerr := requests.\n\tURL(\"http://example.com\").\n\tToString(\u0026s).\n\tFetch(ctx)\n```\n\n### How do I validate the response status?\n\nBy default, if no other validators are added to a builder, requests will check that the response is in the 2XX range. If you add another validator, you can add `builder.CheckStatus(200)` or `builder.AddValidator(requests.DefaultValidator)` to the validation stack.\n\nTo disable all response validation, run `builder.AddValidator(nil)`.\n\n## Contributing\n\nPlease [create a discussion](https://github.com/earthboundkid/requests/discussions) before submitting a pull request for a new feature.\n","funding_links":["https://github.com/sponsors/earthboundkid"],"categories":["Go","Networking"],"sub_categories":["HTTP Clients"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearthboundkid%2Frequests","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fearthboundkid%2Frequests","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearthboundkid%2Frequests/lists"}