1
0
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:
Dr. Carsten Leue
2024-02-08 09:42:29 +01:00
parent 9f6b6d4968
commit 6f91e91eb9
4 changed files with 73 additions and 1 deletions

View File

@@ -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)
} }

View File

@@ -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,

View File

@@ -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)))
}

View File

@@ -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))
}