Skip to content

Commit

Permalink
Add context awareness to http functions
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimirvivien committed Nov 25, 2024
1 parent 53bbca2 commit 96efd03
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 28 deletions.
14 changes: 12 additions & 2 deletions functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,19 +194,29 @@ func FileWrite(path string) *fs.FileWriter {
return DefaultEcho.FileWriteWithContext(context.Background(), path)
}

// HttpGetWithContext uses context ctx to start an HTTP GET operation to retrieve resource at URL/path
func HttpGetWithContext(ctx context.Context, url string, paths ...string) *http.ResourceReader {
return DefaultEcho.HttpGetWithContext(ctx, url, paths...)
}

// HttpGet starts an HTTP GET operation to retrieve resource at URL/path
func HttpGet(url string, paths ...string) *http.ResourceReader {
return DefaultEcho.HttpGet(url, paths...)
return DefaultEcho.HttpGetWithContext(context.Background(), url, paths...)
}

// Get is a convenient alias for HttpGet that retrieves specified resource at given URL/path
func Get(url string, paths ...string) *http.Response {
return DefaultEcho.Get(url, paths...)
}

// HttpPostWithContext uses context ctx to start an HTTP POST operation to post resource to URL/path
func HttpPostWithContext(ctx context.Context, url string, paths ...string) *http.ResourceWriter {
return DefaultEcho.HttpPostWithContext(ctx, url, paths...)
}

// HttpPost starts an HTTP POST operation to post resource to URL/path
func HttpPost(url string, paths ...string) *http.ResourceWriter {
return DefaultEcho.HttpPost(url, paths...)
return DefaultEcho.HttpPostWithContext(context.Background(), url, paths...)
}

// Post is a convenient alias for HttpPost to post data at specified URL
Expand Down
23 changes: 17 additions & 6 deletions http.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
package gexe

import (
"context"
"strings"

"github.com/vladimirvivien/gexe/http"
)

// HttpGet starts an HTTP GET operation to retrieve server resource from given URL/paths.
func (e *Echo) HttpGet(url string, paths ...string) *http.ResourceReader {
// HttpGetWithContext uses context ctx to start an HTTP GET operation to retrieve server resource from given URL/paths.
func (e *Echo) HttpGetWithContext(ctx context.Context, url string, paths ...string) *http.ResourceReader {
var exapandedUrl strings.Builder
exapandedUrl.WriteString(e.vars.Eval(url))
for _, path := range paths {
exapandedUrl.WriteString(e.vars.Eval(path))
}
return http.GetWithVars(exapandedUrl.String(), e.vars)
return http.GetWithContextVars(ctx, exapandedUrl.String(), e.vars)
}

// HttpPost starts an HTTP POST operation to post resource to a server at given URL/path.
func (e *Echo) HttpPost(url string, paths ...string) *http.ResourceWriter {
// HttpGetWithContext starts an HTTP GET operation to retrieve server resource from given URL/paths.
func (e *Echo) HttpGet(url string, paths ...string) *http.ResourceReader {
return e.HttpGetWithContext(context.Background(), url, paths...)
}

// HttpPostWithContext uses context ctx to start an HTTP POST operation to post resource to a server at given URL/path.
func (e *Echo) HttpPostWithContext(ctx context.Context, url string, paths ...string) *http.ResourceWriter {
var exapandedUrl strings.Builder
exapandedUrl.WriteString(e.vars.Eval(url))
for _, path := range paths {
exapandedUrl.WriteString(e.vars.Eval(path))
}
return http.PostWithVars(exapandedUrl.String(), e.vars)
return http.PostWithContextVars(ctx, exapandedUrl.String(), e.vars)
}

// HttpPost starts an HTTP POST operation to post resource to a server at given URL/path.
func (e *Echo) HttpPost(url string, paths ...string) *http.ResourceWriter {
return e.HttpPostWithContext(context.Background(), url, paths...)
}

// Get is convenient alias for HttpGet to retrieve a resource at given URL/path
Expand Down
92 changes: 80 additions & 12 deletions http/http_reader.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,50 @@
package http

import (
"bytes"
"context"
"io"
"net/http"
"strings"
"time"

"github.com/vladimirvivien/gexe/vars"
)

// ResourceReader provides types and methods to read content of resources from a server using HTTP
type ResourceReader struct {
client *http.Client
err error
url string
vars *vars.Variables
client *http.Client
err error
url string
vars *vars.Variables
ctx context.Context
data io.Reader
headers http.Header
}

// Get initiates a "GET" operation for the specified resource
func Get(url string) *ResourceReader {
return &ResourceReader{url: url, client: &http.Client{}, vars: &vars.Variables{}}
// GetWithContextVars uses context ctx and session variables to initiate
// a "GET" operation for the specified resource
func GetWithContextVars(ctx context.Context, url string, variables *vars.Variables) *ResourceReader {
if variables == nil {
variables = &vars.Variables{}
}

return &ResourceReader{
ctx: ctx,
url: variables.Eval(url),
client: &http.Client{},
vars: &vars.Variables{},
}
}

// Get initiates a "GET" operation and sets session variables
// GetWithVars uses session vars to initiate a "GET" operation
func GetWithVars(url string, variables *vars.Variables) *ResourceReader {
r := Get(variables.Eval(url))
r.vars = variables
return r
return GetWithContextVars(context.Background(), url, variables)
}

// Get initiates a "GET" operation for the specified resource
func Get(url string) *ResourceReader {
return GetWithContextVars(context.Background(), url, &vars.Variables{})
}

// SetVars sets session variables for ResourceReader
Expand All @@ -44,12 +64,60 @@ func (r *ResourceReader) WithTimeout(to time.Duration) *ResourceReader {
return r
}

// WithContext sets the context for the HTTP request
func (r *ResourceReader) WithContext(ctx context.Context) *ResourceReader {
r.ctx = ctx
return r
}

// WithHeaders sets all HTTP headers for GET request
func (r *ResourceReader) WithHeaders(h http.Header) *ResourceReader {
r.headers = h
return r
}

// AddHeader convenience method to add request header
func (r *ResourceReader) AddHeader(key, value string) *ResourceReader {
r.headers.Add(r.vars.Eval(key), r.vars.Eval(value))
return r
}

// SetHeader convenience method to set a specific header
func (r *ResourceReader) SetHeader(key, value string) *ResourceReader {
r.headers.Set(r.vars.Eval(key), r.vars.Eval(value))
return r
}

// RequestString sets GET request data as string
func (r *ResourceReader) String(val string) *ResourceReader {
r.data = strings.NewReader(r.vars.Eval(val))
return r
}

// RequestBytes sets GET request data as byte slice
func (r *ResourceReader) Bytes(data []byte) *ResourceReader {
r.data = bytes.NewReader(data)
return r
}

// RequestBody sets GET request content as io.Reader
func (r *ResourceReader) Body(body io.Reader) *ResourceReader {
r.data = body
return r
}

// Do is a terminal method that actually retrieves the HTTP resource from the server.
// It returns a gexe/http/*Response instance that can be used to access the result.
func (r *ResourceReader) Do() *Response {
res, err := r.client.Get(r.url)
req, err := http.NewRequestWithContext(r.ctx, "GET", r.url, r.data)
if err != nil {
return &Response{err: err}
}

res, err := r.client.Do(req)
if err != nil {
return &Response{err: err}
}

return &Response{stat: res.Status, statCode: res.StatusCode, body: res.Body}
}
38 changes: 30 additions & 8 deletions http/http_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package http

import (
"bytes"
"context"
"io"
"net/http"
"net/url"
Expand All @@ -19,18 +20,33 @@ type ResourceWriter struct {
headers http.Header
data io.Reader
vars *vars.Variables
ctx context.Context
}

// Post starts an HTTP "POST" operation using the provided URL.
func Post(resource string) *ResourceWriter {
return &ResourceWriter{url: resource, client: &http.Client{}, headers: make(http.Header), vars: &vars.Variables{}}
// PostWithContextVars uses the specified context ctx and session variable to
// start an HTTP "POST" operation
func PostWithContextVars(ctx context.Context, resource string, variables *vars.Variables) *ResourceWriter {
if variables == nil {
variables = &vars.Variables{}
}

return &ResourceWriter{
ctx: ctx,
url: variables.Eval(resource),
client: &http.Client{},
headers: make(http.Header),
vars: variables,
}
}

// PostWithVars starts an HTTP "POST" operation and sets the provided gexe session variables
// PostWithVars uses session variables to start an HTTP "POST" operation
func PostWithVars(resource string, variables *vars.Variables) *ResourceWriter {
w := Post(variables.Eval(resource))
w.vars = variables
return w
return PostWithContextVars(context.Background(), resource, variables)
}

// Post starts an HTTP "POST" operation using the provided URL.
func Post(resource string) *ResourceWriter {
return PostWithContextVars(context.Background(), resource, &vars.Variables{})
}

// SetVars sets gexe session variables to be used by the post operation
Expand All @@ -45,6 +61,12 @@ func (w *ResourceWriter) WithTimeout(to time.Duration) *ResourceWriter {
return w
}

// WithContext sets the context to be used for the HTTP request
func (w *ResourceWriter) WithContext(ctx context.Context) *ResourceWriter {
w.ctx = ctx
return w
}

// Err returns the last error generated by the ResourceWriter
func (w *ResourceWriter) Err() error {
return w.err
Expand Down Expand Up @@ -98,7 +120,7 @@ func (w *ResourceWriter) FormData(val map[string][]string) *ResourceWriter {
// Do is a terminal method that actually posts the HTTP request to the server.
// It returns a gexe/http/*Response instance that can be used to access post result.
func (w *ResourceWriter) Do() *Response {
req, err := http.NewRequest("POST", w.url, w.data)
req, err := http.NewRequestWithContext(w.ctx, "POST", w.url, w.data)
if err != nil {
return &Response{err: err}
}
Expand Down

0 comments on commit 96efd03

Please sign in to comment.