Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: set client files for autogeneration #483

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: test install test-integ test-docker
.PHONY: test install test-integ test-docker goimports

install:
go get -t -v ./...
Expand All @@ -13,3 +13,8 @@ version ?= latest
test-docker:
curl -s https://raw.githubusercontent.com/sendgrid/sendgrid-oai/HEAD/prism/prism.sh -o prism.sh
version=$(version) bash ./prism.sh

goimports:
go install golang.org/x/tools/cmd/goimports@latest
goimports -w .
go mod tidy
13 changes: 13 additions & 0 deletions client/base_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package client

import (
"net/http"
"net/url"
"time"
)

type BaseClient interface {
SetTimeout(timeout time.Duration)
SendRequest(method string, rawURL string, data url.Values,
headers map[string]interface{}, body ...byte) (*http.Response, error)
}
161 changes: 161 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Package client provides internal utilities for the sendgrid-go client library.
package client

import (
"bytes"
"fmt"
"net/http"
"net/url"
"regexp"
"runtime"
"strings"
"time"

"github.com/sendgrid/sendgrid-go/client/form"
)

var alphanumericRegex *regexp.Regexp
var delimitingRegex *regexp.Regexp

func init() {
alphanumericRegex = regexp.MustCompile(`^[a-zA-Z0-9]*$`)
delimitingRegex = regexp.MustCompile(`\.\d+`)
}

// Credentials store user authentication credentials.
type Credentials struct {
Apikey string
}

func NewCredentials(apikey string) *Credentials {
return &Credentials{Apikey: apikey}
}

// Client encapsulates a standard HTTP backend with authorization.
type Client struct {
*Credentials
HTTPClient *http.Client
UserAgentExtensions []string
}

// default http Client should not follow redirects and return the most recent response.
func defaultHTTPClient() *http.Client {
return &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Timeout: time.Second * 10,
}
}

func (c *Client) basicAuth() (string, string) {
return c.Credentials.Apikey, ""
}

func (c *Client) bearerAuth() string {
return c.Credentials.Apikey
}

// SetTimeout sets the Timeout for HTTP requests.
func (c *Client) SetTimeout(timeout time.Duration) {
if c.HTTPClient == nil {
c.HTTPClient = defaultHTTPClient()
}
c.HTTPClient.Timeout = timeout
}

func extractContentTypeHeader(headers map[string]interface{}) (cType string) {
headerType, ok := headers["Content-Type"]
if !ok {
return urlEncodedContentType
}
return headerType.(string)
}

const (
urlEncodedContentType = "application/x-www-form-urlencoded"
jsonContentType = "application/json"
keepZeros = true
delimiter = '.'
escapee = '\\'
)

func (c *Client) doWithErr(req *http.Request) (*http.Response, error) {
client := c.HTTPClient

if client == nil {
client = defaultHTTPClient()
}

res, err := client.Do(req)
return res, err
}

func setBearerToken(req *http.Request, token string) {
req.Header.Set("Authorization", "Bearer "+token)
}

// SendRequest verifies, constructs, and authorizes an HTTP request.
func (c *Client) SendRequest(method string, rawURL string, data url.Values,
headers map[string]interface{}, body ...byte) (*http.Response, error) {

contentType := extractContentTypeHeader(headers)

u, err := url.Parse(rawURL)
if err != nil {
return nil, err
}

valueReader := &strings.Reader{}
goVersion := runtime.Version()
var req *http.Request

//For HTTP GET Method there are no body parameters. All other parameters like query, path etc
// are added as information in the url itself. Also while Content-Type is json, we are sending
// json body. In that case, data variable contains all other parameters than body, which is the
//same case as GET method. In that case as well all parameters will be added to url
if method == http.MethodGet || contentType == jsonContentType {
if data != nil {
v, _ := form.EncodeToStringWith(data, delimiter, escapee, keepZeros)
s := delimitingRegex.ReplaceAllString(v, "")

u.RawQuery = s
}
}

//data is already processed and information will be added to u(the url) in the
//previous step. Now body will solely contain json payload
if contentType == jsonContentType {
req, err = http.NewRequest(method, u.String(), bytes.NewBuffer(body))
if err != nil {
return nil, err
}
} else {
//Here the HTTP POST methods which is not having json content type are processed
//All the values will be added in data and encoded (all body, query, path parameters)
if method == http.MethodPost || method == http.MethodPut {
valueReader = strings.NewReader(data.Encode())
}
req, err = http.NewRequest(method, u.String(), valueReader)
if err != nil {
return nil, err
}

}

setBearerToken(req, c.bearerAuth())

// E.g. "User-Agent": "sendgrid-go/1.0.0 (darwin amd64) go/go1.17.8"
userAgent := fmt.Sprintf("sendgrid-go/%s (%s %s) go/%s", LibraryVersion, runtime.GOOS, runtime.GOARCH, goVersion)

if len(c.UserAgentExtensions) > 0 {
userAgent += " " + strings.Join(c.UserAgentExtensions, " ")
}

req.Header.Add("User-Agent", userAgent)

for k, v := range headers {
req.Header.Add(k, fmt.Sprint(v))
}
return c.doWithErr(req)
}
Loading
Loading