-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(web/sdk): feeds manager gql client (#1333)
## Motivation Integration tests with job orchestration require a Go client for interacting with the GQL API. ## Solution This PR generates a Go SDK using [genqlient](https://github.com/Khan/genqlient) and exposes it via a `Client` interface defined at `integration-tests/web/sdk`.
- Loading branch information
Showing
12 changed files
with
6,627 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ zig 0.11.0 | |
golangci-lint 1.59.1 | ||
protoc 25.1 | ||
python 3.10.5 | ||
task 3.35.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
## GQL SDK | ||
|
||
This package exports a `Client` for interacting with the `feeds-manager` service of core. The implementation is based on code generated via `[genqlient](https://github.com/Khan/genqlient)`. | ||
|
||
### Extending the Client | ||
|
||
Add additional queries or mutations to `genqlient.graphql` and then regenerate the implementation via the Taskfile: | ||
|
||
```bash | ||
$ task generate | ||
``` | ||
|
||
Next, extend the `Client` interface and the `client` implementation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package client | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/Khan/genqlient/graphql" | ||
|
||
"github.com/smartcontractkit/ccip/integration-tests/web/sdk/client/internal/doer" | ||
"github.com/smartcontractkit/ccip/integration-tests/web/sdk/internal/generated" | ||
) | ||
|
||
type Client interface { | ||
GetCSAKeys(ctx context.Context) (*generated.GetCSAKeysResponse, error) | ||
GetJob(ctx context.Context, id string) (*generated.GetJobResponse, error) | ||
ListJobs(ctx context.Context, offset, limit int) (*generated.ListJobsResponse, error) | ||
GetBridge(ctx context.Context, id string) (*generated.GetBridgeResponse, error) | ||
ListBridges(ctx context.Context, offset, limit int) (*generated.ListBridgesResponse, error) | ||
GetFeedsManager(ctx context.Context, id string) (*generated.GetFeedsManagerResponse, error) | ||
ListFeedsManagers(ctx context.Context) (*generated.ListFeedsManagersResponse, error) | ||
CreateFeedsManager(ctx context.Context, cmd generated.CreateFeedsManagerInput) (*generated.CreateFeedsManagerResponse, error) | ||
UpdateFeedsManager(ctx context.Context, id string, cmd generated.UpdateFeedsManagerInput) (*generated.UpdateFeedsManagerResponse, error) | ||
GetJobProposal(ctx context.Context, id string) (*generated.GetJobProposalResponse, error) | ||
ApproveJobProposalSpec(ctx context.Context, id string, force bool) (*generated.ApproveJobProposalSpecResponse, error) | ||
CancelJobProposalSpec(ctx context.Context, id string) (*generated.CancelJobProposalSpecResponse, error) | ||
RejectJobProposalSpec(ctx context.Context, id string) (*generated.RejectJobProposalSpecResponse, error) | ||
UpdateJobProposalSpecDefinition(ctx context.Context, id string, cmd generated.UpdateJobProposalSpecDefinitionInput) (*generated.UpdateJobProposalSpecDefinitionResponse, error) | ||
} | ||
|
||
type client struct { | ||
gqlClient graphql.Client | ||
credentials Credentials | ||
endpoints endpoints | ||
cookie string | ||
} | ||
|
||
type endpoints struct { | ||
Sessions string | ||
Query string | ||
} | ||
|
||
type Credentials struct { | ||
Email string `json:"email"` | ||
Password string `json:"password"` | ||
} | ||
|
||
func New(baseURI string, creds Credentials) (Client, error) { | ||
endpoints := endpoints{ | ||
Sessions: baseURI + "/sessions", | ||
Query: baseURI + "/query", | ||
} | ||
c := &client{ | ||
endpoints: endpoints, | ||
credentials: creds, | ||
} | ||
|
||
if err := c.login(); err != nil { | ||
return nil, fmt.Errorf("failed to login to node: %w", err) | ||
} | ||
|
||
c.gqlClient = graphql.NewClient( | ||
c.endpoints.Query, | ||
doer.NewAuthed(c.cookie), | ||
) | ||
|
||
return c, nil | ||
} | ||
|
||
func (c *client) GetCSAKeys(ctx context.Context) (*generated.GetCSAKeysResponse, error) { | ||
return generated.GetCSAKeys(ctx, c.gqlClient) | ||
} | ||
|
||
func (c *client) GetJob(ctx context.Context, id string) (*generated.GetJobResponse, error) { | ||
return generated.GetJob(ctx, c.gqlClient, id) | ||
} | ||
|
||
func (c *client) ListJobs(ctx context.Context, offset, limit int) (*generated.ListJobsResponse, error) { | ||
return generated.ListJobs(ctx, c.gqlClient, offset, limit) | ||
} | ||
|
||
func (c *client) GetBridge(ctx context.Context, id string) (*generated.GetBridgeResponse, error) { | ||
return generated.GetBridge(ctx, c.gqlClient, id) | ||
} | ||
|
||
func (c *client) ListBridges(ctx context.Context, offset, limit int) (*generated.ListBridgesResponse, error) { | ||
return generated.ListBridges(ctx, c.gqlClient, offset, limit) | ||
} | ||
|
||
func (c *client) GetFeedsManager(ctx context.Context, id string) (*generated.GetFeedsManagerResponse, error) { | ||
return generated.GetFeedsManager(ctx, c.gqlClient, id) | ||
} | ||
|
||
func (c *client) ListFeedsManagers(ctx context.Context) (*generated.ListFeedsManagersResponse, error) { | ||
return generated.ListFeedsManagers(ctx, c.gqlClient) | ||
} | ||
|
||
func (c *client) CreateFeedsManager(ctx context.Context, cmd generated.CreateFeedsManagerInput) (*generated.CreateFeedsManagerResponse, error) { | ||
return generated.CreateFeedsManager(ctx, c.gqlClient, cmd) | ||
} | ||
|
||
func (c *client) UpdateFeedsManager(ctx context.Context, id string, cmd generated.UpdateFeedsManagerInput) (*generated.UpdateFeedsManagerResponse, error) { | ||
return generated.UpdateFeedsManager(ctx, c.gqlClient, id, cmd) | ||
} | ||
|
||
func (c *client) GetJobProposal(ctx context.Context, id string) (*generated.GetJobProposalResponse, error) { | ||
return generated.GetJobProposal(ctx, c.gqlClient, id) | ||
} | ||
|
||
func (c *client) ApproveJobProposalSpec(ctx context.Context, id string, force bool) (*generated.ApproveJobProposalSpecResponse, error) { | ||
return generated.ApproveJobProposalSpec(ctx, c.gqlClient, id, force) | ||
} | ||
|
||
func (c *client) CancelJobProposalSpec(ctx context.Context, id string) (*generated.CancelJobProposalSpecResponse, error) { | ||
return generated.CancelJobProposalSpec(ctx, c.gqlClient, id) | ||
} | ||
|
||
func (c *client) RejectJobProposalSpec(ctx context.Context, id string) (*generated.RejectJobProposalSpecResponse, error) { | ||
return generated.RejectJobProposalSpec(ctx, c.gqlClient, id) | ||
} | ||
|
||
func (c *client) UpdateJobProposalSpecDefinition(ctx context.Context, id string, cmd generated.UpdateJobProposalSpecDefinitionInput) (*generated.UpdateJobProposalSpecDefinitionResponse, error) { | ||
return generated.UpdateJobProposalSpecDefinition(ctx, c.gqlClient, id, cmd) | ||
} | ||
|
||
func (c *client) login() error { | ||
b, err := json.Marshal(c.credentials) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal credentials: %w", err) | ||
} | ||
|
||
payload := strings.NewReader(string(b)) | ||
|
||
req, err := http.NewRequest("POST", c.endpoints.Sessions, payload) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
req.Header.Add("Content-Type", "application/json") | ||
|
||
res, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
defer res.Body.Close() | ||
|
||
cookieHeader := res.Header.Get("Set-Cookie") | ||
if cookieHeader == "" { | ||
return fmt.Errorf("no cookie found in header") | ||
} | ||
|
||
c.cookie = strings.Split(cookieHeader, ";")[0] | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package doer | ||
|
||
import "net/http" | ||
|
||
type authed struct { | ||
cookie string | ||
wrapped *http.Client | ||
} | ||
|
||
func NewAuthed(cookie string) *authed { | ||
return &authed{ | ||
cookie: cookie, | ||
wrapped: http.DefaultClient, | ||
} | ||
} | ||
|
||
func (a *authed) Do(req *http.Request) (*http.Response, error) { | ||
req.Header.Set("cookie", a.cookie) | ||
return a.wrapped.Do(req) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Default genqlient config; for full documentation see: | ||
# https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml | ||
schema: ./internal/schema.graphql | ||
|
||
operations: | ||
- ./internal/genqlient.graphql | ||
|
||
generated: ./internal/generated/generated.go | ||
|
||
bindings: | ||
Time: | ||
type: string | ||
|
||
package_bindings: | ||
- package: github.com/smartcontractkit/chainlink/v2/core/web/gqlscalar |
Oops, something went wrong.