Package HttpCli :

- slipt package between pure httpcli and request to become new package Request
- Add options to httpcli allowed to create an http client based on options

Package AWS :
- add option for delete object : check boolean to make or not the check (head) before delete
- add exclusion of NoSuchKey error if check is false

Package Request :
- integer option capabilities to configure the request inteface
- use httpcli option to get httpcli (keep custom function to get an *http.client)
- extend function to mode manage the request
This commit is contained in:
Nicolas JUHEL
2022-04-01 13:33:21 +02:00
parent eb0c034074
commit b1f5e42db7
14 changed files with 628 additions and 174 deletions

View File

@@ -52,12 +52,11 @@ func (cli *client) Check() liberr.Error {
func (cli *client) Create(RegionConstraint string) liberr.Error { func (cli *client) Create(RegionConstraint string) liberr.Error {
in := &sdksss.CreateBucketInput{ in := &sdksss.CreateBucketInput{
Bucket: cli.GetBucketAws(), Bucket: cli.GetBucketAws(),
CreateBucketConfiguration: &sdkstp.CreateBucketConfiguration{},
} }
if RegionConstraint != "" { if RegionConstraint != "" {
in.CreateBucketConfiguration = &sdkstp.CreateBucketConfiguration{ in.CreateBucketConfiguration.LocationConstraint = sdkstp.BucketLocationConstraint(RegionConstraint)
LocationConstraint: sdkstp.BucketLocationConstraint(RegionConstraint),
}
} }
out, err := cli.s3.CreateBucket(cli.GetContext(), in) out, err := cli.s3.CreateBucket(cli.GetContext(), in)

View File

@@ -62,7 +62,10 @@ var _ = Describe("Bucket", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(objects).To(HaveLen(1)) Expect(objects).To(HaveLen(1))
err = cli.Object().Delete("object") err = cli.Object().Delete(true, "object")
Expect(err).ToNot(HaveOccurred())
err = cli.Object().Delete(false, "object")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
}) })

View File

@@ -50,7 +50,7 @@ type Object interface {
Head(object string) (*sdksss.HeadObjectOutput, liberr.Error) Head(object string) (*sdksss.HeadObjectOutput, liberr.Error)
Get(object string) (*sdksss.GetObjectOutput, liberr.Error) Get(object string) (*sdksss.GetObjectOutput, liberr.Error)
Put(object string, body io.Reader) liberr.Error Put(object string, body io.Reader) liberr.Error
Delete(object string) liberr.Error Delete(check bool, object string) liberr.Error
MultipartPut(object string, body io.Reader) liberr.Error MultipartPut(object string, body io.Reader) liberr.Error
MultipartPutCustom(partSize libhlp.PartSize, object string, body io.Reader) liberr.Error MultipartPutCustom(partSize libhlp.PartSize, object string, body io.Reader) liberr.Error

View File

@@ -29,9 +29,11 @@ import (
"io" "io"
"mime" "mime"
"path/filepath" "path/filepath"
"strings"
sdksss "github.com/aws/aws-sdk-go-v2/service/s3"
sdkaws "github.com/aws/aws-sdk-go-v2/aws" sdkaws "github.com/aws/aws-sdk-go-v2/aws"
sdksss "github.com/aws/aws-sdk-go-v2/service/s3"
sdktps "github.com/aws/aws-sdk-go-v2/service/s3/types" sdktps "github.com/aws/aws-sdk-go-v2/service/s3/types"
libhlp "github.com/nabbar/golib/aws/helper" libhlp "github.com/nabbar/golib/aws/helper"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
@@ -129,16 +131,25 @@ func (cli *client) Put(object string, body io.Reader) liberr.Error {
return nil return nil
} }
func (cli *client) Delete(object string) liberr.Error { func (cli *client) Delete(check bool, object string) liberr.Error {
if check {
if _, err := cli.Head(object); err != nil { if _, err := cli.Head(object); err != nil {
return err return err
} }
}
_, err := cli.s3.DeleteObject(cli.GetContext(), &sdksss.DeleteObjectInput{ _, err := cli.s3.DeleteObject(cli.GetContext(), &sdksss.DeleteObjectInput{
Bucket: cli.GetBucketAws(), Bucket: cli.GetBucketAws(),
Key: sdkaws.String(object), Key: sdkaws.String(object),
}) })
if !check && err != nil {
e := err.Error()
if strings.Contains(e, "api error NoSuchKey") {
return nil
}
}
return cli.GetError(err) return cli.GetError(err)
} }

View File

@@ -62,8 +62,8 @@ var _ = Describe("Object", func() {
}) })
Context("Delete object", func() { Context("Delete object", func() {
It("Must fail as the object doesn't exists - 4", func() { It("Must fail as the bucket doesn't exists - 4", func() {
err := cli.Object().Delete("object") err := cli.Object().Delete(true, "object")
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
}) })
@@ -75,11 +75,17 @@ var _ = Describe("Object", func() {
}) })
}) })
Context("Delete object", func() { Context("Delete object no check", func() {
It("Must fail as the object doesn't exists - 6", func() { It("Must fail as the bucket doesn't exists - 6", func() {
err := cli.Object().Delete("object") err := cli.Object().Delete(false, "object")
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
}) })
Context("Delete object with check", func() {
It("Must fail as the bucket doesn't exists - 6", func() {
err := cli.Object().Delete(true, "object")
Expect(err).To(HaveOccurred())
})
})
}) })

View File

@@ -49,12 +49,13 @@ const (
MinPkgNutsDB = 2000 MinPkgNutsDB = 2000
MinPkgOAuth = 2100 MinPkgOAuth = 2100
MinPkgAws = 2200 MinPkgAws = 2200
MinPkgRouter = 2300 MinPkgRequest = 2300
MinPkgSemaphore = 2400 MinPkgRouter = 2400
MinPkgSMTP = 2500 MinPkgSemaphore = 2500
MinPkgStatic = 2600 MinPkgSMTP = 2600
MinPkgVersion = 2700 MinPkgStatic = 2700
MinPkgViper = 2800 MinPkgVersion = 2800
MinPkgViper = 2900
MinAvailable = 4000 MinAvailable = 4000

View File

@@ -33,12 +33,7 @@ import (
const ( const (
ErrorParamsEmpty liberr.CodeError = iota + liberr.MinPkgHttpCli ErrorParamsEmpty liberr.CodeError = iota + liberr.MinPkgHttpCli
ErrorParamsInvalid ErrorParamsInvalid
ErrorCreateRequest ErrorValidatorError
ErrorSendRequest
ErrorResponseInvalid
ErrorResponseLoadBody
ErrorResponseStatus
ErrorResponseUnmarshall
ErrorClientTransportHttp2 ErrorClientTransportHttp2
) )
@@ -59,18 +54,8 @@ func getMessage(code liberr.CodeError) (message string) {
return "at least one given parameters is empty" return "at least one given parameters is empty"
case ErrorParamsInvalid: case ErrorParamsInvalid:
return "at least one given parameters is invalid" return "at least one given parameters is invalid"
case ErrorCreateRequest: case ErrorValidatorError:
return "cannot create http request for given params" return "config seems to be invalid"
case ErrorSendRequest:
return "cannot send the http request"
case ErrorResponseInvalid:
return "the response for the sending request seems to be invalid"
case ErrorResponseLoadBody:
return "an error occurs while trying to load the response contents"
case ErrorResponseStatus:
return "the response status is not in the valid status list"
case ErrorResponseUnmarshall:
return "the response body cannot be unmarshal with given model"
case ErrorClientTransportHttp2: case ErrorClientTransportHttp2:
return "error while configure http2 transport for client" return "error while configure http2 transport for client"
} }

75
httpcli/options.go Normal file
View File

@@ -0,0 +1,75 @@
package httpcli
import (
"fmt"
"net/http"
"time"
libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
)
type OptionForceIP struct {
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
Net string `json:"net,omitempty" yaml:"net,omitempty" toml:"net,omitempty" mapstructure:"net,omitempty"`
IP string `json:"ip,omitempty" yaml:"ip,omitempty" toml:"ip,omitempty" mapstructure:"ip,omitempty"`
}
type OptionTLS struct {
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
Config libtls.Config `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`
}
type Options struct {
Timeout time.Duration `json:"timeout" yaml:"timeout" toml:"timeout" mapstructure:"timeout"`
Http2 bool `json:"http2" yaml:"http2" toml:"http2" mapstructure:"http2"`
TLS OptionTLS `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`
ForceIP OptionForceIP `json:"force_ip" yaml:"force_ip" toml:"force_ip" mapstructure:"force_ip"`
}
func (o Options) Validate() liberr.Error {
var e = ErrorValidatorError.Error(nil)
if err := libval.New().Struct(o); err != nil {
if er, ok := err.(*libval.InvalidValidationError); ok {
e.AddParent(er)
}
for _, er := range err.(libval.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", er.Namespace(), er.ActualTag()))
}
}
if !e.HasParent() {
e = nil
}
return e
}
func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Client, liberr.Error) {
var tls libtls.TLSConfig
if t, e := o._GetTLS(def); e != nil {
return nil, e
} else {
tls = t
}
if o.ForceIP.Enable {
return GetClientTlsForceIp(GetNetworkFromString(o.ForceIP.Net), o.ForceIP.IP, servername, tls, o.Http2, o.Timeout)
} else {
return GetClientTls(servername, tls, o.Http2, o.Timeout)
}
}
func (o Options) _GetTLS(def libtls.TLSConfig) (libtls.TLSConfig, liberr.Error) {
if o.TLS.Enable {
return o.TLS.Config.NewFrom(def)
} else {
return libtls.Default.Clone(), nil
}
}

View File

@@ -31,7 +31,7 @@ import (
"os" "os"
"strings" "strings"
valid "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
) )
@@ -174,12 +174,12 @@ func (o Options) RegisterFuncUpdateLevel(fct FuncCustomConfig) {
func (o *Options) Validate() liberr.Error { func (o *Options) Validate() liberr.Error {
var e = ErrorValidatorError.Error(nil) var e = ErrorValidatorError.Error(nil)
if err := valid.New().Struct(o); err != nil { if err := libval.New().Struct(o); err != nil {
if er, ok := err.(*valid.InvalidValidationError); ok { if er, ok := err.(*libval.InvalidValidationError); ok {
e.AddParent(er) e.AddParent(er)
} }
for _, er := range err.(valid.ValidationErrors) { for _, er := range err.(libval.ValidationErrors) {
//nolint #goerr113 //nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", er.Namespace(), er.ActualTag())) e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", er.Namespace(), er.ActualTag()))
} }

View File

@@ -24,7 +24,7 @@
* *
*/ */
package httpcli package request
import "bytes" import "bytes"

79
request/errors.go Normal file
View File

@@ -0,0 +1,79 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package request
import (
liberr "github.com/nabbar/golib/errors"
)
const (
ErrorParamsEmpty liberr.CodeError = iota + liberr.MinPkgRequest
ErrorParamsInvalid
ErrorValidatorError
ErrorCreateRequest
ErrorSendRequest
ErrorResponseInvalid
ErrorResponseLoadBody
ErrorResponseStatus
ErrorResponseUnmarshall
)
func init() {
isCodeError = liberr.ExistInMapMessage(ErrorParamsEmpty)
liberr.RegisterIdFctMessage(ErrorParamsEmpty, getMessage)
}
var isCodeError = false
func IsCodeError() bool {
return isCodeError
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case ErrorParamsEmpty:
return "at least one given parameters is empty"
case ErrorParamsInvalid:
return "at least one given parameters is invalid"
case ErrorValidatorError:
return "config seems to be invalid"
case ErrorCreateRequest:
return "cannot create http request for given params"
case ErrorSendRequest:
return "cannot send the http request"
case ErrorResponseInvalid:
return "the response for the sending request seems to be invalid"
case ErrorResponseLoadBody:
return "an error occurs while trying to load the response contents"
case ErrorResponseStatus:
return "the response status is not in the valid status list"
case ErrorResponseUnmarshall:
return "the response body cannot be unmarshal with given model"
}
return liberr.NUL_MESSAGE
}

View File

@@ -24,7 +24,7 @@
* *
*/ */
package httpcli package request
import ( import (
"bytes" "bytes"
@@ -33,14 +33,14 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"sync" "sync"
"time"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
) )
type FctHttpClient func() *http.Client type FctHttpClient func(def libtls.TLSConfig, servername string) *http.Client
type FctTLSDefault func() libtls.TLSConfig
type RequestError interface { type RequestError interface {
StatusCode() int StatusCode() int
@@ -50,38 +50,54 @@ type RequestError interface {
} }
type Request interface { type Request interface {
Clone() Request Clone() (Request, error)
New() Request New() (Request, error)
GetOption() *Options
SetOption(opt *Options) error
SetClient(fct FctHttpClient) SetClient(fct FctHttpClient)
UseClientPackage(ip string, tls libtls.TLSConfig, http2Tr bool, GlobalTimeout time.Duration)
Endpoint(uri string) error SetEndpoint(u string) error
SetUrl(u *url.URL) GetEndpoint() string
GetUrl() *url.URL
AddPath(path string) SetPath(raw bool, path string)
AddPath(raw bool, path ...string)
SetMethod(mtd string)
GetMethod() string
CleanParams()
DelParams(key string)
SetParams(key, val string)
AddParams(key, val string) AddParams(key, val string)
GetFullUrl() *url.URL
SetFullUrl(u *url.URL)
AuthBearer(token string) AuthBearer(token string)
AuthBasic(user, pass string) AuthBasic(user, pass string)
ContentType(content string) ContentType(content string)
Header(key, value string) CleanHeader()
Method(mtd string) DelHeader(key string)
SetHeader(key, value string)
AddHeader(key, value string)
RequestJson(body interface{}) error BodyJson(body interface{}) error
RequestReader(body io.Reader) BodyReader(body io.Reader, contentType string)
Error() RequestError Error() RequestError
IsError() bool
Do(ctx context.Context) (*http.Response, liberr.Error) Do(ctx context.Context) (*http.Response, liberr.Error)
DoParse(ctx context.Context, model interface{}, validStatus ...int) liberr.Error DoParse(ctx context.Context, model interface{}, validStatus ...int) liberr.Error
} }
func New(fct FctHttpClient) Request { func New(fct FctHttpClient, opt Options) (Request, error) {
return &request{ r := &request{
s: sync.Mutex{}, s: sync.Mutex{},
f: fct, o: nil,
f: nil,
u: nil, u: nil,
h: make(url.Values), h: make(url.Values),
p: make(url.Values), p: make(url.Values),
@@ -89,4 +105,12 @@ func New(fct FctHttpClient) Request {
m: http.MethodGet, m: http.MethodGet,
e: nil, e: nil,
} }
r.SetClient(fct)
if e := r.SetOption(&opt); e != nil {
return nil, e
} else {
return r, nil
}
} }

View File

@@ -24,7 +24,7 @@
* *
*/ */
package httpcli package request
import ( import (
"bytes" "bytes"
@@ -37,7 +37,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
"time" "sync/atomic"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
@@ -47,6 +47,7 @@ import (
type request struct { type request struct {
s sync.Mutex s sync.Mutex
o *atomic.Value
f FctHttpClient f FctHttpClient
u *url.URL u *url.URL
h url.Values h url.Values
@@ -56,11 +57,87 @@ type request struct {
e *requestError e *requestError
} }
func (r *request) Clone() Request { func (r *request) _GetDefaultTLS() libtls.TLSConfig {
n := &request{ if cfg := r.GetOption(); cfg != nil {
s: sync.Mutex{}, return cfg._GetDefaultTLS()
f: r.f, }
u: &url.URL{
return nil
}
func (r *request) _GetClient() *http.Client {
var h string
if r.u != nil {
h = r.u.Hostname()
}
if r.f != nil {
if c := r.f(r._GetDefaultTLS(), h); c != nil {
return c
}
}
if cfg := r.GetOption(); cfg != nil {
return cfg.GetClientHTTP(h)
}
return &http.Client{}
}
func (r *request) _IsValidCode(listValid []int, statusCode int) bool {
if len(listValid) < 1 {
return true
}
for _, c := range listValid {
if c == statusCode {
return true
}
}
return false
}
func (r *request) Clone() (Request, error) {
if n, e := r.New(); e != nil {
return nil, e
} else {
r.s.Lock()
defer r.s.Unlock()
n.CleanHeader()
for k := range r.h {
n.SetHeader(k, r.h.Get(k))
}
n.CleanParams()
for k := range r.p {
n.SetParams(k, r.p.Get(k))
}
return n, nil
}
}
func (r *request) New() (Request, error) {
cfg := r.GetOption()
r.s.Lock()
defer r.s.Unlock()
var n *request
if cfg == nil {
if i, e := New(r.f, Options{}); e != nil {
return nil, e
} else {
n = i.(*request)
}
}
if r.u != nil {
n.u = &url.URL{
Scheme: r.u.Scheme, Scheme: r.u.Scheme,
Opaque: r.u.Opaque, Opaque: r.u.Opaque,
User: r.u.User, User: r.u.User,
@@ -71,110 +148,87 @@ func (r *request) Clone() Request {
RawQuery: r.u.RawQuery, RawQuery: r.u.RawQuery,
Fragment: r.u.Fragment, Fragment: r.u.Fragment,
RawFragment: r.u.RawFragment, RawFragment: r.u.RawFragment,
},
h: make(url.Values),
p: make(url.Values),
b: r.b,
m: http.MethodGet,
e: nil,
}
for k, v := range r.h {
n.h[k] = v
}
for k, v := range r.p {
n.p[k] = v
}
return n
}
func (r *request) New() Request {
return &request{
s: sync.Mutex{},
f: r.f,
u: nil,
h: make(url.Values),
p: make(url.Values),
b: bytes.NewBuffer(make([]byte, 0)),
m: http.MethodGet,
e: nil,
} }
} }
func (r *request) _GetClient() *http.Client { return n, nil
if r.f != nil { }
if c := r.f(); c != nil {
return c func (r *request) GetOption() *Options {
r.s.Lock()
defer r.s.Unlock()
if r.o == nil {
return nil
} else if i := r.o.Load(); i == nil {
return nil
} else if o, ok := i.(*Options); !ok {
return nil
} else {
return o
} }
} }
return &http.Client{} func (r *request) SetOption(opt *Options) error {
if e := r.SetEndpoint(opt.Endpoint); e != nil {
return e
}
if opt.Auth.Basic.Enable {
r.AuthBasic(opt.Auth.Basic.Username, opt.Auth.Basic.Password)
} else if opt.Auth.Bearer.Enable {
r.AuthBearer(opt.Auth.Bearer.Token)
}
r.s.Lock()
defer r.s.Unlock()
if r.o == nil {
r.o = new(atomic.Value)
}
r.o.Store(opt)
return nil
} }
func (r *request) SetClient(fct FctHttpClient) { func (r *request) SetClient(fct FctHttpClient) {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
r.f = fct r.f = fct
} }
func (r *request) UseClientPackage(ip string, tls libtls.TLSConfig, http2Tr bool, GlobalTimeout time.Duration) { func (r *request) SetEndpoint(u string) error {
r.s.Lock() if uri, err := url.Parse(u); err != nil {
defer r.s.Unlock() return err
if tls == nil {
tls = libtls.Default
}
if len(ip) > 0 {
r.f = func() *http.Client {
if h, e := GetClientTlsForceIp(NetworkTCP, ip, r.u.Hostname(), tls, http2Tr, GlobalTimeout); e == nil {
return h
} else if h, e = GetClientTimeout(r.u.Hostname(), false, GlobalTimeout); e == nil {
return h
}
return &http.Client{}
}
} else {
r.f = func() *http.Client {
if h, e := GetClientTls(r.u.Hostname(), tls, http2Tr, GlobalTimeout); e == nil {
return h
} else if h, e = GetClientTls(r.u.Hostname(), tls, false, GlobalTimeout); e == nil {
return h
}
return &http.Client{}
}
}
}
func (r *request) Endpoint(uri string) error {
if u, e := url.Parse(uri); e != nil {
return e
} else { } else {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
r.u = u
}
r.u = uri
return nil return nil
} }
func (r *request) SetUrl(u *url.URL) {
r.s.Lock()
defer r.s.Unlock()
r.u = u
} }
func (r *request) GetUrl() *url.URL { func (r *request) GetEndpoint() string {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
return r.u
return r.u.String()
} }
func (r *request) AddPath(path string) { func (r *request) SetPath(raw bool, path string) {
r.s.Lock()
defer r.s.Unlock()
if raw {
r.u.RawPath = path
} else {
r.u.Path = path
}
}
func (r *request) AddPath(raw bool, path ...string) {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
@@ -182,15 +236,85 @@ func (r *request) AddPath(path string) {
return return
} }
if strings.HasPrefix(path, "/") { for i := range path {
path = strings.TrimPrefix(path, "/") if strings.HasPrefix(path[i], "/") {
path[i] = strings.TrimPrefix(path[i], "/")
} }
if strings.HasSuffix(path, "/") { if strings.HasSuffix(path[i], "/") {
path = strings.TrimSuffix(path, "/") path[i] = strings.TrimSuffix(path[i], "/")
} }
r.u.Path = filepath.Join(r.u.Path, path) if raw {
r.u.RawPath = filepath.Join(r.u.RawPath, path[i])
} else {
r.u.Path = filepath.Join(r.u.Path, path[i])
}
}
}
func (r *request) SetMethod(method string) {
r.s.Lock()
defer r.s.Unlock()
switch strings.ToUpper(method) {
case http.MethodGet:
r.m = http.MethodGet
case http.MethodHead:
r.m = http.MethodHead
case http.MethodPost:
r.m = http.MethodPost
case http.MethodPut:
r.m = http.MethodPut
case http.MethodPatch:
r.m = http.MethodPatch
case http.MethodDelete:
r.m = http.MethodDelete
case http.MethodConnect:
r.m = http.MethodConnect
case http.MethodOptions:
r.m = http.MethodOptions
case http.MethodTrace:
r.m = http.MethodTrace
default:
r.m = strings.ToUpper(method)
}
if r.m == "" {
r.m = http.MethodGet
}
}
func (r *request) GetMethod() string {
r.s.Lock()
defer r.s.Unlock()
return r.m
}
func (r *request) CleanParams() {
r.s.Lock()
defer r.s.Unlock()
r.p = make(url.Values)
}
func (r *request) DelParams(key string) {
r.s.Lock()
defer r.s.Unlock()
r.p.Del(key)
}
func (r *request) SetParams(key, val string) {
r.s.Lock()
defer r.s.Unlock()
if len(r.p) < 1 {
r.p = make(url.Values)
}
r.p.Set(key, val)
} }
func (r *request) AddParams(key, val string) { func (r *request) AddParams(key, val string) {
@@ -204,19 +328,47 @@ func (r *request) AddParams(key, val string) {
r.p.Set(key, val) r.p.Set(key, val)
} }
func (r *request) GetFullUrl() *url.URL {
r.s.Lock()
defer r.s.Unlock()
return r.u
}
func (r *request) SetFullUrl(u *url.URL) {
r.s.Lock()
defer r.s.Unlock()
r.u = u
}
func (r *request) AuthBearer(token string) { func (r *request) AuthBearer(token string) {
r.Header("Authorization", "Bearer "+token) r.SetHeader("Authorization", "Bearer "+token)
} }
func (r *request) AuthBasic(user, pass string) { func (r *request) AuthBasic(user, pass string) {
r.Header("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(user+":"+pass))) r.SetHeader("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(user+":"+pass)))
} }
func (r *request) ContentType(content string) { func (r *request) ContentType(content string) {
r.Header("Content-Type", content) r.SetHeader("Content-Type", content)
} }
func (r *request) Header(key, value string) { func (r *request) CleanHeader() {
r.s.Lock()
defer r.s.Unlock()
r.h = make(url.Values)
}
func (r *request) DelHeader(key string) {
r.s.Lock()
defer r.s.Unlock()
r.h.Del(key)
}
func (r *request) SetHeader(key, value string) {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
@@ -227,14 +379,18 @@ func (r *request) Header(key, value string) {
r.h.Set(key, value) r.h.Set(key, value)
} }
func (r *request) Method(mtd string) { func (r *request) AddHeader(key, value string) {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
r.m = mtd if len(r.h) < 1 {
r.h = make(url.Values)
} }
func (r *request) RequestJson(body interface{}) error { r.h.Add(key, value)
}
func (r *request) BodyJson(body interface{}) error {
if p, e := json.Marshal(body); e != nil { if p, e := json.Marshal(body); e != nil {
return e return e
} else { } else {
@@ -248,11 +404,15 @@ func (r *request) RequestJson(body interface{}) error {
return nil return nil
} }
func (r *request) RequestReader(body io.Reader) { func (r *request) BodyReader(body io.Reader, contentType string) {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
r.b = body r.b = body
if contentType != "" {
r.ContentType(contentType)
}
} }
func (r *request) Error() RequestError { func (r *request) Error() RequestError {
@@ -262,6 +422,13 @@ func (r *request) Error() RequestError {
return r.e return r.e
} }
func (r *request) IsError() bool {
r.s.Lock()
defer r.s.Unlock()
return r.e != nil
}
func (r *request) Do(ctx context.Context) (*http.Response, liberr.Error) { func (r *request) Do(ctx context.Context) (*http.Response, liberr.Error) {
r.s.Lock() r.s.Lock()
defer r.s.Unlock() defer r.s.Unlock()
@@ -381,17 +548,3 @@ func (r *request) DoParse(ctx context.Context, model interface{}, validStatus ..
return nil return nil
} }
func (r *request) _IsValidCode(listValid []int, statusCode int) bool {
if len(listValid) < 1 {
return true
}
for _, c := range listValid {
if c == statusCode {
return true
}
}
return false
}

118
request/options.go Normal file
View File

@@ -0,0 +1,118 @@
package request
import (
"fmt"
"net/http"
libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
libhtc "github.com/nabbar/golib/httpcli"
libsts "github.com/nabbar/golib/status"
)
type OptionsCredentials struct {
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
Username string `json:"username" yaml:"username" toml:"username" mapstructure:"username"`
Password string `json:"password" yaml:"password" toml:"password" mapstructure:"password"`
}
type OptionsToken struct {
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
Token string `json:"token" yaml:"token" toml:"token" mapstructure:"token"`
}
type OptionsAuth struct {
Basic OptionsCredentials `json:"basic" yaml:"basic" toml:"basic" mapstructure:"basic" validate:"required,dive"`
Bearer OptionsToken `json:"bearer" yaml:"bearer" toml:"bearer" mapstructure:"bearer" validate:"required,dive"`
}
type OptionsHealth struct {
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
Endpoint string `json:"endpoint" yaml:"endpoint" toml:"endpoint" mapstructure:"endpoint" validate:"required,url"`
Auth OptionsAuth `json:"auth" yaml:"auth" toml:"auth" mapstructure:"auth" validate:"required,dive"`
Status libsts.ConfigStatus `json:"status" yaml:"status" toml:"status" mapstructure:"status" validate:"required,dive"`
}
type Options struct {
Endpoint string `json:"endpoint" yaml:"endpoint" toml:"endpoint" mapstructure:"endpoint" validate:"required,url"`
HttpClient libhtc.Options `json:"http_client" yaml:"http_client" toml:"http_client" mapstructure:"http_client" validate:"required,dive"`
Auth OptionsAuth `json:"auth" yaml:"auth" toml:"auth" mapstructure:"auth" validate:"required,dive"`
Health OptionsHealth `json:"health" yaml:"health" toml:"health" mapstructure:"health" validate:"required,dive"`
def FctTLSDefault
}
func (o Options) Validate() liberr.Error {
var e = ErrorValidatorError.Error(nil)
if err := libval.New().Struct(o); err != nil {
if er, ok := err.(*libval.InvalidValidationError); ok {
e.AddParent(er)
}
for _, er := range err.(libval.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", er.Namespace(), er.ActualTag()))
}
}
if !e.HasParent() {
e = nil
}
return e
}
func (o Options) _GetDefaultTLS() libtls.TLSConfig {
if o.def != nil {
return o.def()
}
return nil
}
func (o Options) SetDefaultTLS(fct FctTLSDefault) {
o.def = fct
}
func (o Options) GetClientHTTP(servername string) *http.Client {
if c, e := o.HttpClient.GetClient(o._GetDefaultTLS(), servername); e == nil {
return c
}
return &http.Client{}
}
func (o Options) New(cli FctHttpClient, tls FctTLSDefault) (Request, error) {
if tls != nil {
o.def = tls
}
return New(cli, o)
}
func (o Options) Update(req Request, cli FctHttpClient, tls FctTLSDefault) (Request, error) {
if tls != nil {
o.def = tls
}
var (
e error
n Request
)
if n, e = req.Clone(); e != nil {
return nil, e
}
if cli != nil {
n.SetClient(cli)
}
if e = n.SetOption(&o); e != nil {
return nil, e
}
return n, nil
}