-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cleanup to limit scope to Get options
- Loading branch information
1 parent
736856a
commit ecafc76
Showing
7 changed files
with
211 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,50 @@ | ||
package api | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"net/url" | ||
|
||
"github.com/defenseunicorns/lula/src/types" | ||
) | ||
|
||
func (a ApiDomain) makeRequests(_ context.Context) (types.DomainResources, error) { | ||
collection := make(map[string]interface{}, 0) | ||
|
||
// defaultOpts apply to all requests, but may be overridden by adding an | ||
// options block to an individual request. | ||
var defaultOpts *ApiOpts | ||
if a.Spec.Options == nil { | ||
defaultOpts = new(ApiOpts) | ||
} else { | ||
defaultOpts = a.Spec.Options | ||
} | ||
|
||
// configure the default HTTP client using any top-level Options. Individual | ||
// requests with overrides will get bespoke clients. | ||
transport := &http.Transport{} | ||
if defaultOpts.Proxy != "" { | ||
proxy, err := url.Parse(a.Spec.Options.Proxy) | ||
if err != nil { | ||
return nil, fmt.Errorf("error parsing proxy url: %s", err) | ||
} | ||
transport.Proxy = http.ProxyURL(proxy) | ||
} | ||
|
||
defaultClient := &http.Client{Transport: transport} | ||
if defaultOpts.timeout != nil { | ||
defaultClient.Timeout = *defaultOpts.timeout | ||
} | ||
|
||
for _, request := range a.Spec.Requests { | ||
resp, err := defaultClient.Get(request.URL) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if resp.StatusCode != 200 { | ||
return nil, | ||
fmt.Errorf("expected status code 200 but got %d", resp.StatusCode) | ||
func (a ApiDomain) makeRequests(ctx context.Context) (types.DomainResources, error) { | ||
select { | ||
case <-ctx.Done(): | ||
return nil, fmt.Errorf("canceled: %s", ctx.Err()) | ||
default: | ||
collection := make(map[string]interface{}, 0) | ||
|
||
// defaultOpts apply to all requests, but may be overridden by adding an | ||
// options block to an individual request. | ||
var defaultOpts *ApiOpts | ||
if a.Spec.Options == nil { | ||
// This isn't likely to be nil in real usage, since CreateApiDomain | ||
// parses and mutates specs. | ||
defaultOpts = new(ApiOpts) | ||
} else { | ||
defaultOpts = a.Spec.Options | ||
} | ||
|
||
defer resp.Body.Close() | ||
body, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// configure the default HTTP client using any top-level Options. Individual | ||
// requests with overrides will get bespoke clients. | ||
defaultClient := clientFromOpts(defaultOpts) | ||
|
||
contentType := resp.Header.Get("Content-Type") | ||
if contentType == "application/json" { | ||
for _, request := range a.Spec.Requests { | ||
var responseType map[string]interface{} | ||
var err error | ||
|
||
var prettyBuff bytes.Buffer | ||
err := json.Indent(&prettyBuff, body, "", " ") | ||
if err != nil { | ||
return nil, err | ||
if request.Options == nil { | ||
responseType, err = doHTTPReq(defaultClient, *request.reqURL, defaultOpts.Headers, request.reqParameters, responseType) | ||
} else { | ||
client := clientFromOpts(request.Options) | ||
responseType, err = doHTTPReq(client, *request.reqURL, request.Options.Headers, request.reqParameters, responseType) | ||
} | ||
prettyJson := prettyBuff.String() | ||
|
||
var tempData interface{} | ||
err = json.Unmarshal([]byte(prettyJson), &tempData) | ||
if err != nil { | ||
return nil, err | ||
} | ||
collection[request.Name] = tempData | ||
|
||
} else { | ||
return nil, fmt.Errorf("content type %s is not supported", contentType) | ||
collection[request.Name] = responseType | ||
} | ||
return collection, nil | ||
} | ||
return collection, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package api | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
) | ||
|
||
func doHTTPReq[T any](client http.Client, url url.URL, headers map[string]string, queryParameters url.Values, respTy T) (T, error) { | ||
// append any query parameters. | ||
q := url.Query() | ||
|
||
for k, v := range queryParameters { | ||
// using Add instead of set incase the input URL already had a query encoded | ||
q.Add(k, strings.Join(v, ",")) | ||
} | ||
// set the query to the encoded parameters | ||
url.RawQuery = q.Encode() | ||
|
||
req, err := http.NewRequest(http.MethodGet, url.String(), nil) | ||
if err != nil { | ||
return respTy, err | ||
} | ||
|
||
// add each header to the request | ||
for k, v := range headers { | ||
req.Header.Set(k, v) | ||
} | ||
|
||
// do the thing | ||
res, err := client.Do(req) | ||
if err != nil { | ||
return respTy, err | ||
} | ||
|
||
if res == nil { | ||
return respTy, fmt.Errorf("error: calling %s returned empty response", url.Redacted()) | ||
} | ||
defer res.Body.Close() | ||
|
||
responseData, err := io.ReadAll(res.Body) | ||
if err != nil { | ||
return respTy, err | ||
} | ||
|
||
if res.StatusCode != http.StatusOK { | ||
return respTy, fmt.Errorf("expected status code 200 but got %d", res.StatusCode) | ||
} | ||
|
||
var responseObject T | ||
err = json.Unmarshal(responseData, &responseObject) | ||
|
||
if err != nil { | ||
return respTy, fmt.Errorf("error unmarshaling response: %w", err) | ||
} | ||
|
||
return responseObject, nil | ||
} | ||
|
||
func clientFromOpts(opts *ApiOpts) http.Client { | ||
transport := &http.Transport{} | ||
if opts.proxyURL != nil { | ||
transport.Proxy = http.ProxyURL(opts.proxyURL) | ||
} | ||
c := http.Client{Transport: transport} | ||
if opts.timeout != nil { | ||
c.Timeout = *opts.timeout | ||
} | ||
return c | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,5 +127,4 @@ func TestValidateAndMutateSpec(t *testing.T) { | |
} | ||
}) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.