mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: add hash to http builder
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
@@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
package bytes
|
package bytes
|
||||||
|
|
||||||
|
func Empty() []byte {
|
||||||
|
return Monoid.Empty()
|
||||||
|
}
|
||||||
|
|
||||||
func ToString(a []byte) string {
|
func ToString(a []byte) string {
|
||||||
return string(a)
|
return string(a)
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,7 @@ import (
|
|||||||
func TestBuilderWithQuery(t *testing.T) {
|
func TestBuilderWithQuery(t *testing.T) {
|
||||||
// add some query
|
// add some query
|
||||||
withLimit := R.WithQueryArg("limit")("10")
|
withLimit := R.WithQueryArg("limit")("10")
|
||||||
withURL := R.WithUrl("http://www.example.org?a=b")
|
withURL := R.WithURL("http://www.example.org?a=b")
|
||||||
|
|
||||||
b := F.Pipe2(
|
b := F.Pipe2(
|
||||||
R.Default,
|
R.Default,
|
||||||
|
@@ -16,9 +16,14 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
B "github.com/IBM/fp-go/bytes"
|
||||||
E "github.com/IBM/fp-go/either"
|
E "github.com/IBM/fp-go/either"
|
||||||
ENDO "github.com/IBM/fp-go/endomorphism"
|
ENDO "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
@@ -29,6 +34,7 @@ import (
|
|||||||
LZ "github.com/IBM/fp-go/lazy"
|
LZ "github.com/IBM/fp-go/lazy"
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
L "github.com/IBM/fp-go/optics/lens"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
|
R "github.com/IBM/fp-go/record"
|
||||||
S "github.com/IBM/fp-go/string"
|
S "github.com/IBM/fp-go/string"
|
||||||
T "github.com/IBM/fp-go/tuple"
|
T "github.com/IBM/fp-go/tuple"
|
||||||
)
|
)
|
||||||
@@ -138,6 +144,9 @@ var (
|
|||||||
WithBytes,
|
WithBytes,
|
||||||
ENDO.Chain(WithContentType(C.FormEncoded)),
|
ENDO.Chain(WithContentType(C.FormEncoded)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// bodyAsBytes returns a []byte with a fallback to the empty array
|
||||||
|
bodyAsBytes = O.Fold(B.Empty, E.Fold(F.Ignore1of1[error](B.Empty), F.Identity[[]byte]))
|
||||||
)
|
)
|
||||||
|
|
||||||
func setRawQuery(u *url.URL, raw string) *url.URL {
|
func setRawQuery(u *url.URL, raw string) *url.URL {
|
||||||
@@ -272,6 +281,11 @@ func (builder *Builder) GetHeaderValues(name string) []string {
|
|||||||
return builder.headers.Values(name)
|
return builder.headers.Values(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHash returns a hash value for the builder that can be used as a cache key
|
||||||
|
func (builder *Builder) GetHash() string {
|
||||||
|
return MakeHash(builder)
|
||||||
|
}
|
||||||
|
|
||||||
// Header returns a [L.Lens] for a single header
|
// Header returns a [L.Lens] for a single header
|
||||||
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
||||||
get := getHeader(name)
|
get := getHeader(name)
|
||||||
@@ -342,3 +356,32 @@ func WithQueryArg(name string) func(value string) Endomorphism {
|
|||||||
func WithoutQueryArg(name string) Endomorphism {
|
func WithoutQueryArg(name string) Endomorphism {
|
||||||
return QueryArg(name).Set(noQueryArg)
|
return QueryArg(name).Set(noQueryArg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashWriteValue(buf *bytes.Buffer, value string) *bytes.Buffer {
|
||||||
|
buf.WriteString(value)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashWriteQuery(name string, buf *bytes.Buffer, values []string) *bytes.Buffer {
|
||||||
|
buf.WriteString(name)
|
||||||
|
return A.Reduce(hashWriteValue, buf)(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBytes(b *Builder) []byte {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
buf.WriteString(b.GetMethod())
|
||||||
|
buf.WriteString(b.GetURL())
|
||||||
|
b.GetHeaders().Write(&buf) // #nosec: G104
|
||||||
|
|
||||||
|
R.ReduceOrdWithIndex[[]string, *bytes.Buffer](S.Ord)(hashWriteQuery, &buf)(b.GetQuery())
|
||||||
|
|
||||||
|
buf.Write(bodyAsBytes(b.GetBody()))
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeHash converts a [Builder] into a hash string, convenient to use as a cache key
|
||||||
|
func MakeHash(b *Builder) string {
|
||||||
|
return fmt.Sprintf("%x", sha256.Sum256(makeBytes(b)))
|
||||||
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
@@ -66,3 +67,27 @@ func TestWithFormData(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, C.FormEncoded, Headers.Get(res).Get(H.ContentType))
|
assert.Equal(t, C.FormEncoded, Headers.Get(res).Get(H.ContentType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHash(t *testing.T) {
|
||||||
|
|
||||||
|
b1 := F.Pipe4(
|
||||||
|
Default,
|
||||||
|
WithContentType(C.JSON),
|
||||||
|
WithHeader(H.Accept)(C.JSON),
|
||||||
|
WithURL("http://www.example.com"),
|
||||||
|
WithJSON(map[string]string{"a": "b"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
b2 := F.Pipe4(
|
||||||
|
Default,
|
||||||
|
WithURL("http://www.example.com"),
|
||||||
|
WithHeader(H.Accept)(C.JSON),
|
||||||
|
WithContentType(C.JSON),
|
||||||
|
WithJSON(map[string]string{"a": "b"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, MakeHash(b1), MakeHash(b2))
|
||||||
|
assert.NotEqual(t, MakeHash(Default), MakeHash(b2))
|
||||||
|
|
||||||
|
fmt.Println(MakeHash(b1))
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user