package ezhttp import ( "bytes" "encoding/base64" "encoding/json" "io" "net/http" urlpkg "net/url" "strings" ) type RequestModifier func(r *RequestBuilder) *RequestBuilder type ValueProvider[T any] func() T type AuthProvider ValueProvider[string] type RequestBodyProvider func() (io.Reader, string) func Request(mods ...RequestModifier) (*http.Request, error) { r := NewRequestBuilder() for _, mod := range mods { r = mod(r) } return r.Build() } func Template(req *http.Request) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { return NewRequestBuilderFromRequest(req) } } func URL(url string) RequestModifier { parsedUrl, err := urlpkg.Parse(url) if err != nil { panic(err) } return func(r *RequestBuilder) *RequestBuilder { r.URL = parsedUrl return r //return Headers("Host", parsedUrl.Host)(r) } } func Scheme(scheme string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { r.URL.Scheme = scheme return r } } func Host(host string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { r.URL.Host = host return r } } func Path(path string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { r.URL.Path = path return r } } func AppendPath(path ...string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { r.URL = r.URL.JoinPath(path...) return r } } func Fragment(fragment string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { r.URL.Fragment = fragment return r } } func Query(keyValuePairs ...string) RequestModifier { if len(keyValuePairs)%2 != 0 { panic("keyValuePairs must have an even length") } return func(r *RequestBuilder) *RequestBuilder { q := r.URL.Query() for i := 0; i < len(keyValuePairs)-1; i += 2 { q.Add(keyValuePairs[i], keyValuePairs[i+1]) } r.URL.RawQuery = q.Encode() return r } } func QueryMap(query map[string]string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { q := r.URL.Query() for key, value := range query { q.Add(key, value) } r.URL.RawQuery = q.Encode() return r } } func Method(method string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { r.Method = method return r } } func Headers(keyValuePairs ...string) RequestModifier { if len(keyValuePairs)%2 != 0 { panic("keyValuePairs must have an even length") } return func(r *RequestBuilder) *RequestBuilder { for i := 0; i < len(keyValuePairs)-1; i += 2 { r.Header.Add(keyValuePairs[i], keyValuePairs[i+1]) } return r } } func HeadersMap(headers map[string]string) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { for key, value := range headers { r.Header.Add(key, value) } return r } } func Auth(auth AuthProvider) RequestModifier { return Headers("Authentication", auth()) } func Basic(username, password string) AuthProvider { return func() string { return "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password)) } } func Bearer(token string) AuthProvider { return func() string { return "Bearer " + token } } func ContentType(contentType string) RequestModifier { return Headers("Content-Type", contentType) } func Body(bodyProvider RequestBodyProvider) RequestModifier { return func(r *RequestBuilder) *RequestBuilder { body, contentType := bodyProvider() r.Body = body if contentType != "" && r.Header.Get("Content-Type") != "" { r.Header.Set("Content-Type", contentType) } return r } } func Reader(r io.Reader) RequestBodyProvider { return func() (io.Reader, string) { return r, "application/octet-stream" } } func String(s string) RequestBodyProvider { return func() (io.Reader, string) { return strings.NewReader(s), "text/plain" } } func Bytes(b []byte) RequestBodyProvider { return func() (io.Reader, string) { return bytes.NewReader(b), "application/octet-stream" } } func JSON[T any](value T) RequestBodyProvider { buf := bytes.NewBuffer(make([]byte, 0, 1024)) if err := json.NewEncoder(buf).Encode(value); err != nil { panic(err) } return func() (io.Reader, string) { return buf, "application/json" } }