Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 45 additions & 8 deletions pkg/engine/datasource/rest_datasource/rest_datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/buger/jsonparser"
"io"
"net/http"
"regexp"
Expand All @@ -23,6 +25,10 @@ type Planner struct {
operationDefinition int
}

const (
typeString = "String"
)

func (p *Planner) DownstreamResponseFieldAlias(_ int) (alias string, exists bool) {
// the REST DataSourcePlanner doesn't rewrite upstream fields: skip
return
Expand Down Expand Up @@ -65,16 +71,17 @@ type SubscriptionConfiguration struct {
}

type FetchConfiguration struct {
URL string
Method string
Header http.Header
Query []QueryConfiguration
Body string
URL string
Method string
Header http.Header
Query []QueryConfiguration
Body string
}

type QueryConfiguration struct {
Name string `json:"name"`
Value string `json:"value"`
Name string `json:"name"`
Value string `json:"value"`
rawMessage json.RawMessage
}

func (p *Planner) Register(visitor *plan.Visitor, configuration plan.DataSourceConfiguration, isNested bool) error {
Expand All @@ -100,7 +107,7 @@ func (p *Planner) configureInput() []byte {
}

preparedQuery := p.prepareQueryParams(p.rootField, p.config.Fetch.Query)
query, err := json.Marshal(preparedQuery)
query, err := p.marshalQueryParams(preparedQuery)
if err == nil && len(preparedQuery) != 0 {
input = httpclient.SetInputQueryParams(input, query)
}
Expand Down Expand Up @@ -152,6 +159,18 @@ Next:
if value.Kind != ast.ValueKindVariable {
continue Next
}

variableDefRef, exists := p.v.Operation.VariableDefinitionByNameAndOperation(p.operationDefinition, p.v.Operation.VariableValueNameBytes(value.Ref))
if !exists {
continue
}
typeRef := p.v.Operation.VariableDefinitions[variableDefRef].Type
typeName := p.v.Operation.TypeNameString(typeRef)
query[i].rawMessage = []byte(`"` + query[i].Value + `"`)
if p.v.Operation.Types[typeRef].TypeKind == ast.TypeKindList || (typeName != "" && typeName != typeString) {
Comment thread
kofoworola marked this conversation as resolved.
Outdated
query[i].rawMessage = []byte(query[i].Value)
}

variableName := p.v.Operation.VariableValueNameString(value.Ref)
if !p.v.Operation.OperationDefinitionHasVariableDefinition(p.operationDefinition, variableName) {
continue Next
Expand All @@ -163,6 +182,24 @@ Next:
return out
}

func (p *Planner) marshalQueryParams(params []QueryConfiguration) ([]byte, error) {
marshalled, err := json.Marshal(params)
if err != nil {
return nil, err
}
for i := range params {
if params[i].rawMessage != nil {
marshalled, err = jsonparser.Set(marshalled, params[i].rawMessage, fmt.Sprintf("[%d]", i), "value")
} else {
marshalled, err = jsonparser.Set(marshalled, []byte(`"`+params[i].Value+`"`), fmt.Sprintf("[%d]", i), "value")
}
if err != nil {
return nil, err
}
}
return marshalled, nil
}

type Source struct {
client *http.Client
}
Expand Down
85 changes: 84 additions & 1 deletion pkg/engine/datasource/rest_datasource/rest_datasource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
friend: Friend
withArgument(id: String!, name: String, optional: String): Friend
withArrayArguments(names: [String]): Friend
withIntArgument(limit: Int): Friend
}

type Subscription {
Expand All @@ -45,6 +46,7 @@ const (
name: String
pet: Pet
phone(name: String!): String
hasArg(limit: Int!): String
}

type Pet {
Expand Down Expand Up @@ -119,6 +121,14 @@ const (
}
`

intArgumentOperation = `
query ArgumentQuery {
withIntArgument(limit: 10) {
name
}
}
`

createFriendOperation = `
mutation CreateFriend($friendVariable: InputFriend!) {
createFriend(friend: $friendVariable) {
Expand Down Expand Up @@ -1019,7 +1029,7 @@ func TestFastHttpJsonDataSourcePlanning(t *testing.T) {
Data: &resolve.Object{
Fetch: &resolve.SingleFetch{
BufferId: 0,
Input: `{"query_params":[{"name":"names","value":"$$0$$"}],"method":"GET","url":"https://example.com/friend"}`,
Input: `{"query_params":[{"name":"names","value":$$0$$}],"method":"GET","url":"https://example.com/friend"}`,
DataSource: &Source{},
Variables: resolve.NewVariables(
&resolve.ContextVariable{
Expand Down Expand Up @@ -1086,6 +1096,79 @@ func TestFastHttpJsonDataSourcePlanning(t *testing.T) {
DisableResolveFieldPositions: true,
},
))
t.Run("get request with int argument query", datasourcetesting.RunTest(schema, intArgumentOperation, "ArgumentQuery",
&plan.SynchronousResponsePlan{
Response: &resolve.GraphQLResponse{
Data: &resolve.Object{
Fetch: &resolve.SingleFetch{
BufferId: 0,
Input: `{"query_params":[{"name":"limit","value":$$0$$}],"method":"GET","url":"https://example.com/friend"}`,
DataSource: &Source{},
Variables: resolve.NewVariables(
&resolve.ContextVariable{
Path: []string{"a"},
Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["integer","null"]}`),
},
),
DataSourceIdentifier: []byte("rest_datasource.Source"),
DisableDataLoader: true,
},
Fields: []*resolve.Field{
{
BufferID: 0,
HasBuffer: true,
Name: []byte("withIntArgument"),
Value: &resolve.Object{
Nullable: true,
Fields: []*resolve.Field{
{
Name: []byte("name"),
Value: &resolve.String{
Path: []string{"name"},
Nullable: true,
},
},
},
},
},
},
},
},
},
plan.Configuration{
DataSources: []plan.DataSourceConfiguration{
{
RootNodes: []plan.TypeField{
{
TypeName: "Query",
FieldNames: []string{"withIntArgument"},
},
},
Custom: ConfigJSON(Configuration{
Fetch: FetchConfiguration{
URL: "https://example.com/friend",
Method: "GET",
Query: []QueryConfiguration{
{
Name: "limit",
Value: "{{ .arguments.limit }}",
},
},
},
}),
Factory: &Factory{},
},
},
Fields: []plan.FieldConfiguration{
{
TypeName: "Query",
FieldName: "withIntArgument",
DisableDefaultMapping: true,
},
},
DisableResolveFieldPositions: true,
},
))
t.Run("get request with array query", datasourcetesting.RunTest(schema, arrayArgumentOperation, "ArgumentQuery",
&plan.SynchronousResponsePlan{
Response: &resolve.GraphQLResponse{
Expand Down