Skip to content

Commit

Permalink
refactor: v2.0 code feat: add UrlBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
xfali committed Jul 21, 2022
1 parent 8751c75 commit 52fe072
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 9 deletions.
4 changes: 2 additions & 2 deletions cookie/cookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func (dm *defaultCache) Set(path string, cookie *http.Cookie) error {

func checkCookiePath(path string, cookie *http.Cookie) {
if cookie.Path == "" {
if path == "" || path== "/" {
if path == "" || path == "/" {
cookie.Path = "/"
} else {
index := strings.LastIndex(path, "/")
Expand Down Expand Up @@ -312,7 +312,7 @@ func (dm *defaultCache) Filter(request *http.Request, fc filter.FilterChain) (*h
return resp, err
}

func Filter(cache Cache) filter.Filter {
func Filter(cache Cache) filter.Filter {
return func(request *http.Request, fc filter.FilterChain) (response *http.Response, e error) {
path := request.URL.String()
for _, v := range cache.Get(path) {
Expand Down
1 change: 0 additions & 1 deletion cookie/cookie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package cookie
import (
"context"
"fmt"
"github.com/xfali/restclient/v2"
"github.com/xfali/restclient/v2/request"
"github.com/xfali/restclient/v2/restutil"
"net/http"
Expand Down
16 changes: 11 additions & 5 deletions default_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,12 +398,18 @@ func (c *YamlConverter) CreateDecoder(r io.Reader) Decoder {
return &YamlDecoder{d: yaml.NewDecoder(r)}
}

func NewYamlConverter() *YamlConverter {
func NewYamlConverter(supportTypes ...string) *YamlConverter {
types := []MediaType{
ParseMediaType(MediaTypeYaml),
BuildMediaType("application", "*yaml"),
}
for _, t := range supportTypes {
types = append(types, ParseMediaType(t))
}
return &YamlConverter{
BaseConverter{[]MediaType{
ParseMediaType(MediaTypeYaml),
BuildMediaType("application", "*yaml"),
}},
BaseConverter{
types,
},
}
}

Expand Down
16 changes: 16 additions & 0 deletions param.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ func (p *defaultParam) Header(header http.Header) *defaultParam {
return p
}

func (p *defaultParam) AddHeaders(key string, values ...string) *defaultParam {
for _, v := range values {
p.header.Add(key, v)
}
return p
}

func (p *defaultParam) SetHeader(key string, value string) *defaultParam {
p.header.Set(key, value)
return p
}

func (p *defaultParam) Accept(accept string) *defaultParam {
p.header.Add(restutil.HeaderAccept, accept)
return p
Expand Down Expand Up @@ -172,3 +184,7 @@ func (p *defaultParam) self(setter request.Setter) {
func (p *defaultParam) Build() request.Opt {
return p.self
}

func NewUrlBuilder(url string) *restutil.UrlBuilder {
return restutil.NewUrlBuilder(url)
}
130 changes: 130 additions & 0 deletions restutil/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,133 @@ func TestPlaceholderUrl(t *testing.T) {
t.Log(url)
})
}

func TestEncodeQuery(t *testing.T) {
t.Run("1", func(t *testing.T) {
url, err := Query("a", "1", "b", 2)
if err != nil {
t.Fatal(err)
}
if url != "a=1&b=2" {
t.Fatal(url)
}

t.Log(url)
})

t.Run("2", func(t *testing.T) {
url := EncodeQuery(map[string]interface{}{
"a": "1",
"b": 2,
})
if url != "a=1&b=2" {
t.Fatal(url)
}

t.Log(url)
})
}

func TestReplaceUrl(t *testing.T) {
t.Run("1", func(t *testing.T) {
url := ReplaceUrl("x", "", "", map[string]interface{}{
"a": "1",
"b": 2,
})
if url != "x" {
t.Fatal(url)
}

t.Log(url)
})

t.Run("2", func(t *testing.T) {
url := ReplaceUrl("x/:a/tt?b=:b", ":", "", map[string]interface{}{
"a": "1",
"b": 2,
})
if url != "x/1/tt?b=2" {
t.Fatal(url)
}

t.Log(url)
})

t.Run("3", func(t *testing.T) {
url := ReplaceUrl("x/:a/tt/:a?b=:b", ":", "", map[string]interface{}{
"a": "1",
"b": 2,
})
if url != "x/1/tt/1?b=2" {
t.Fatal(url)
}

t.Log(url)
})
}

func TestUrlBuilder(t *testing.T) {
t.Run("1", func(t *testing.T) {
b := NewUrlBuilder("x")
b.PathVariable("a", "1")
b.PathVariable("b", 2)
url := b.Build()
if url != "x" {
t.Fatal(url)
}

t.Log(url)
})

t.Run("2", func(t *testing.T) {
b := NewUrlBuilder("x/:a/tt?b=:b")
b.PathVariable("a", "1")
b.PathVariable("b", 2)
url := b.Build()
if url != "x/1/tt?b=2" {
t.Fatal(url)
}

t.Log(url)
})

t.Run("3", func(t *testing.T) {
b := NewUrlBuilder("x/:a/tt/:a?b=:b")
b.PathVariable("a", "1")
b.PathVariable("b", 2)
url := b.Build()
if url != "x/1/tt/1?b=2" {
t.Fatal(url)
}

t.Log(url)
})

t.Run("4", func(t *testing.T) {
b := NewUrlBuilder("x/:a/tt/:b")
b.PathVariable("a", "1")
b.PathVariable("b", 2)
b.QueryVariable("c", 100)
b.QueryVariable("d", 1.1)
url := b.Build()
if url != "x/1/tt/2?c=100&d=1.1" {
t.Fatal(url)
}

t.Log(url)
})

t.Run("4", func(t *testing.T) {
b := NewUrlBuilder("x/:a/tt/:b?")
b.PathVariable("a", "1")
b.PathVariable("b", 2)
b.QueryVariable("c", 100)
b.QueryVariable("d", 1.1)
url := b.Build()
if url != "x/1/tt/2?c=100&d=1.1" {
t.Fatal(url)
}

t.Log(url)
})
}
112 changes: 111 additions & 1 deletion restutil/urlutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@

package restutil

import "strings"
import (
"bytes"
"fmt"
"net/url"
"reflect"
"strings"
)

func QueryUrl(url string, params map[string]string) string {
url = strings.TrimSpace(url)
Expand Down Expand Up @@ -59,3 +65,107 @@ func PlaceholderUrl(url string, params map[string]string) string {

return url
}

func Query(keyAndValue ...interface{}) (string, error) {
if len(keyAndValue) == 0 {
return "", nil
}
if len(keyAndValue)%2 != 0 {
return "", fmt.Errorf("Query parameter missing value, size is %d ", len(keyAndValue))
}
m := make(map[string]interface{}, len(keyAndValue)/2)
for i := 0; i < len(keyAndValue); i += 2 {
if k, ok := keyAndValue[i].(string); ok {
m[k] = keyAndValue[i+1]
} else {
fmt.Errorf("Query key must be string, but get %s ", reflect.TypeOf(keyAndValue[i]).String())
}
}
return EncodeQuery(m), nil
}

func EncodeQuery(keyAndValue map[string]interface{}) string {
if len(keyAndValue) == 0 {
return ""
}
buf := bytes.Buffer{}
for k, v := range keyAndValue {
buf.WriteString(url.QueryEscape(fmt.Sprintf("%v", k)))
buf.WriteString("=")
buf.WriteString(url.QueryEscape(fmt.Sprintf("%v", v)))
buf.WriteString("&")
}
format := buf.String()
format = format[:len(format)-1]
return format
}

func ReplaceUrl(uri string, leftDelim string, rightDelim string, keyAndValue map[string]interface{}) string {
if len(keyAndValue) == 0 {
return uri
}
for k, v := range keyAndValue {
uri = strings.Replace(uri, fmt.Sprintf("%s%v%s", leftDelim, k, rightDelim), url.QueryEscape(fmt.Sprintf("%v", v)), -1)
}
return uri
}

type UrlBuilder struct {
url string
leftDelim string
rightDelim string
path map[string]interface{}
query map[string]interface{}
}

func NewUrlBuilder(url string) *UrlBuilder {
return &UrlBuilder{
url: url,
leftDelim: ":",
}
}

func (b *UrlBuilder) WithDelim(leftDelim, rightDelim string) *UrlBuilder {
b.leftDelim = leftDelim
b.rightDelim = rightDelim
return b
}

func (b *UrlBuilder) PathVariable(key string, value interface{}) *UrlBuilder {
if b.path == nil {
b.path = map[string]interface{}{}
}
b.path[key] = value
return b
}

func (b *UrlBuilder) QueryVariable(key string, value interface{}) *UrlBuilder {
if b.query == nil {
b.query = map[string]interface{}{}
}
b.query[key] = value
return b
}

func (b *UrlBuilder) Build() string {
buf := strings.Builder{}
if len(b.path) > 0 {
buf.WriteString(ReplaceUrl(b.url, b.leftDelim, b.rightDelim, b.path))
} else {
buf.WriteString(b.url)
}
if len(b.query) > 0 {
query := EncodeQuery(b.query)
if b.url[len(b.url)-1] == '?' {
buf.WriteString(query)
} else {
buf.WriteString("?")
buf.WriteString(query)
}
}
return buf.String()
}

func (b *UrlBuilder) String() string {
return b.Build()
}
14 changes: 14 additions & 0 deletions test/restclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,3 +482,17 @@ func TestErrorStruct(t *testing.T) {
t.Log(ret)
})
}

func TestUrlBuilder(t *testing.T) {
b := restclient.NewUrlBuilder("x/:a/tt/:b?")
b.PathVariable("a", "1")
b.PathVariable("b", 2)
b.QueryVariable("c", 100)
b.QueryVariable("d", 1.1)
url := b.Build()
if url != "x/1/tt/2?c=100&d=1.1" {
t.Fatal(url)
}

t.Log(url)
}

0 comments on commit 52fe072

Please sign in to comment.