https://github.com/mitranim/gr
Short for "Go Request-Response". Shortcuts for making HTTP requests and reading HTTP responses in Go.
https://github.com/mitranim/gr
go golang http request response
Last synced: 3 months ago
JSON representation
Short for "Go Request-Response". Shortcuts for making HTTP requests and reading HTTP responses in Go.
- Host: GitHub
- URL: https://github.com/mitranim/gr
- Owner: mitranim
- License: unlicense
- Created: 2021-11-13T14:53:11.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2023-08-31T13:49:58.000Z (over 2 years ago)
- Last Synced: 2025-02-24T06:44:38.621Z (11 months ago)
- Topics: go, golang, http, request, response
- Language: Go
- Homepage: https://pkg.go.dev/github.com/mitranim/gr
- Size: 70.3 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
Awesome Lists containing this project
README
## Overview
"gr" stands for for **G**o **R**equest or **Go** **R**equest-**R**esponse. It also represents my reaction to many APIs in "net/http". Shortcuts for making HTTP requests and reading HTTP responses. Features:
* Brevity!
* **No added wrappers or interfaces**. Just aliases for `http.Request` and `http.Response`, freely-castable back and forth.
* Fluent chainable builder API.
* Most methods are nullary or unary. No syntactic overhead for features you don't use.
* No overhead over "lower-level" uses of `http.Request` and `http.Response`. Many shortcuts are more performant than "standard" approaches.
* Resulting requests can be passed to any code that takes `http.Request`.
* Usable for `http.Response` responses obtained from any source.
* Tiny and dependency-free.
API docs: https://pkg.go.dev/github.com/mitranim/gr.
## Usage
Sending and receiving JSON:
```golang
package gr_test
import (
"fmt"
"net/url"
"github.com/mitranim/gr"
)
func ExampleReq_jsonInputJsonOutput() {
input := Input{`some input`}
var output Output
gr.To(testServer.URL).Path(`/json`).Json(input).Res().Ok().Json(&output)
fmt.Printf("%#v\n", output)
// Output:
// gr_test.Output{ReqMethod:"GET", ReqUrl:"/json", ReqBody:"{\"inputVal\":\"some input\"}"}
}
type Input struct {
InputVal string `json:"inputVal"`
}
type Output struct {
ReqMethod string `json:"reqMethod"`
ReqUrl string `json:"reqUrl"`
ReqBody string `json:"reqBody"`
}
```
Sending URL-encoded form, reading plain text:
```golang
package gr_test
import (
"fmt"
"net/url"
"github.com/mitranim/gr"
)
func ExampleReq_formBodyPlainResponse() {
req := gr.To(testServer.URL).Post().FormVals(url.Values{`one`: {`two`}})
res := req.Res().Ok()
defer res.Done()
fmt.Printf("\nresponse status: %v\n", res.StatusCode)
fmt.Printf("\nresponse type: %v\n", res.Header.Get(gr.Type))
fmt.Printf("\nresponse body:\n%v\n", res.ReadString())
// Output:
//
// response status: 200
//
// response type: text/plain; charset=utf-8
//
// response body:
//
// request method: POST
// request URL: /
// request body: one=two
}
```
## Why Pointers
Since `gr` uses a chainable builder-style API, we could have defined all "builder" methods on `gr.Req` and `gr.Res` (non-pointer types), rather than on `*gr.Req` and `*gr.Res` (pointer types). This would allow to store "partially built" requests, and "fork" them by simply reassigning variables. So why do we define this on pointer types?
* In Go, request and response are inherently mutable because they contain reference types such as `*url.URL`, `http.Header` and `io.ReadCloser`. Copying structs such as `http.Request` or `http.Response` by reassigning variables makes a shallow copy where the inner references are still mutably shared. That would be hazardous. Explicit copying via `.Clone` is less error prone.
* Emulating an "immutable" API by using copy-on-write for URL and headers is possible, but incurs a measurable performance penalty.
* All APIs in `"net/http"` operate on requests and responses by pointer. By using the same pointers, we avoid the overhead of copying and reallocation.
* Go request and response structs are rather large. The language seems to use naive call conventions that involve always copying value types, as opposed to passing them by reference when they would be constant. For large structs, always passing them by pointer rather than by value seems faster.
## License
https://unlicense.org
## Misc
I'm receptive to suggestions. If this library _almost_ satisfies you but needs changes, open an issue or chat me up. Contacts: https://mitranim.com/#contacts