Skip to content

Commit

Permalink
feat(before_request): impl/allow editing req body, or setting it if nil
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre Fenoll <[email protected]>
  • Loading branch information
fenollp committed Nov 11, 2024
1 parent 41fb36d commit 68b22cb
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 11 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ def add_special_headers(ctx):
token = monkey.env("DEV_API_TOKEN", "dev token is unset!")
req.headers.set("authorization".title(), "Bearer " + token)

# Let's edit (a possibly-empty) body
if req.body == None:
req.body = {}
req.body["key"] = 42

monkey.check(
name = "adds_special_headers",
before_request = add_special_headers,
Expand Down
5 changes: 5 additions & 0 deletions fuzzymonkey.star
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ def add_special_headers(ctx):
token = monkey.env("DEV_API_TOKEN", "dev token is unset!")
req.headers.set("authorization".title(), "Bearer " + token)

# Let's edit (a possibly-empty) body
if req.body == None:
req.body = {}
req.body["key"] = 42

monkey.check(
name = "adds_special_headers",
before_request = add_special_headers,
Expand Down
36 changes: 25 additions & 11 deletions pkg/runtime/cx_request_before_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,26 @@ type cxRequestBeforeRequest struct {

method, url starlark.String
headers *cxHead
body *structpb.Value //FIXME: starlark.Value + test that edits .body (as num and as dict/list, and as set)
body starlark.Value
}

func newCxRequestBeforeRequest(input *fm.Srv_Call_Input) *cxRequestBeforeRequest {
switch x := input.GetInput().(type) {

case *fm.Srv_Call_Input_HttpRequest_:
r := input.GetHttpRequest()
// var bodyValue starlark.Value = starlark.None
var bodyValue starlark.Value = nil
if body := r.GetBody(); body != nil {
bodyValue = starlarkvalue.FromProtoValue(body)
}
return &cxRequestBeforeRequest{
ty: cxRequestHttp,
method: starlark.String(r.GetMethod()),
url: starlark.String(r.GetUrl()),
headers: newcxHead(r.GetHeaders()),
//content: absent as encoding will only happen later
body: r.GetBody(),
body: bodyValue,
}

default:
Expand All @@ -55,24 +60,25 @@ func (cr *cxRequestBeforeRequest) IntoProto(err error) *fm.Clt_CallRequestRaw {
switch cr.ty {
case cxRequestHttp:
var body []byte
var bodyDecoded *structpb.Value
if cr.body != nil {
if body, err = protojson.Marshal(cr.body); err != nil {
bodyDecoded = starlarkvalue.ToProtoValue(cr.body)
if body, err = protojson.Marshal(bodyDecoded); err != nil {
log.Println("[ERR]", err)
// return after sending msg
if len(reason) == 0 && err != nil {
reason = strings.Split(err.Error(), "\n")
}
}
}
//TODO: impl ToProtoValue
return &fm.Clt_CallRequestRaw_Input{
Input: &fm.Clt_CallRequestRaw_Input_HttpRequest_{
HttpRequest: &fm.Clt_CallRequestRaw_Input_HttpRequest{
Method: string(cr.method),
Url: string(cr.url),
Headers: cr.headers.IntoProto(),
Body: body,
BodyDecoded: cr.body,
BodyDecoded: bodyDecoded,
}}}

default:
Expand All @@ -97,8 +103,10 @@ func (cr *cxRequestBeforeRequest) Truth() starlark.Bool { return true }
func (cr *cxRequestBeforeRequest) Type() string { return cr.ty }

func (cr *cxRequestBeforeRequest) Freeze() {
// cr.body.Freeze() FIXME
cr.body.Freeze()
cr.headers.Freeze()
cr.method.Freeze()
cr.url.Freeze()
}

func (cr *cxRequestBeforeRequest) AttrNames() []string {
Expand All @@ -113,13 +121,10 @@ func (cr *cxRequestBeforeRequest) AttrNames() []string {
func (cr *cxRequestBeforeRequest) Attr(name string) (starlark.Value, error) {
switch name {
case "body":
var body starlark.Value = starlark.None
if cr.body != nil {
body = starlarkvalue.FromProtoValue(cr.body)
return cr.body, nil
}
body.Freeze()
// TODO: call ProtoCompatible here
return body, nil
return starlark.None, nil
case "headers":
return cr.headers, nil
case "method":
Expand All @@ -130,3 +135,12 @@ func (cr *cxRequestBeforeRequest) Attr(name string) (starlark.Value, error) {
return nil, nil // no such method
}
}

var _ starlark.HasSetField = (*cxRequestBeforeRequest)(nil)

func (cr *cxRequestBeforeRequest) SetField(name string, val starlark.Value) error {
if name == "body" && cr.body == nil {
cr.body = val
}
return nil
}
69 changes: 69 additions & 0 deletions pkg/starlarkvalue/to_protovalue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package starlarkvalue

import (
"fmt"

"go.starlark.net/starlark"
"google.golang.org/protobuf/types/known/structpb"
)

// ToProtoValue converts a Starlark value to a Google Well-Known-Type value.
// Panics on unexpected starlark value.
func ToProtoValue(x starlark.Value) *structpb.Value {
switch x := x.(type) {

case starlark.NoneType:
return &structpb.Value{Kind: &structpb.Value_NullValue{
NullValue: structpb.NullValue_NULL_VALUE}}

case starlark.Bool:
return &structpb.Value{Kind: &structpb.Value_BoolValue{
BoolValue: bool(x)}}

case starlark.Float:
return &structpb.Value{Kind: &structpb.Value_NumberValue{
NumberValue: float64(x)}}

case starlark.Int:
if x, ok := x.Int64(); ok {
return &structpb.Value{Kind: &structpb.Value_NumberValue{
NumberValue: float64(x)}}
}
panic(fmt.Errorf("unexpected value of type %s: %s", x.Type(), x.String()))

case starlark.String:
return &structpb.Value{Kind: &structpb.Value_StringValue{
StringValue: x.GoString()}}

case *starlark.List:
n := x.Len()
vs := make([]*structpb.Value, 0, n)
for i := 0; i < n; i++ {
vs = append(vs, ToProtoValue(x.Index(i)))
}
return &structpb.Value{Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{
Values: vs}}}

// case starlark.Tuple: // Encodes starlark.Tuple as array.
// n := x.Len()
// vs := make([]*structpb.Value, 0, n)
// for i := 0; i < n; i++ {
// vs = append(vs, ToProtoValue(x.Index(i)))
// }
// return &structpb.Value{Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{
// Values: vs}}}

case *starlark.Dict:
vs := make(map[string]*structpb.Value, x.Len())
for _, kv := range x.Items() {
k := kv.Index(0).(starlark.String).GoString()
v := ToProtoValue(kv.Index(1))
vs[k] = v
}
return &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: &structpb.Struct{
Fields: vs}}}

default:
panic(fmt.Errorf("unexpected value of type %s: %s", x.Type(), x.String()))
}
}

0 comments on commit 68b22cb

Please sign in to comment.