From 3550faf07903ec6f69fb8fe99bf05038c74ffe8c Mon Sep 17 00:00:00 2001 From: Giannis Katsanos Date: Wed, 7 Feb 2024 19:03:07 +0200 Subject: [PATCH] feat: Clients API (#223) Added operations for the Clients API; Get, Verify and List. Added types for Client and Session. --- clerktest/clerktest.go | 10 ++++- client.go | 20 ++++++++++ client/api.go | 31 ++++++++++++++++ client/client.go | 81 ++++++++++++++++++++++++++++++++++++++++ client/client_test.go | 84 ++++++++++++++++++++++++++++++++++++++++++ session.go | 19 ++++++++++ 6 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 client.go create mode 100644 client/api.go create mode 100644 client/client.go create mode 100644 client/client_test.go create mode 100644 session.go diff --git a/clerktest/clerktest.go b/clerktest/clerktest.go index cec403be..cd048ba0 100644 --- a/clerktest/clerktest.go +++ b/clerktest/clerktest.go @@ -6,6 +6,7 @@ import ( "encoding/json" "io" "net/http" + "net/url" "testing" "github.com/stretchr/testify/require" @@ -24,6 +25,8 @@ type RoundTripper struct { Method string // Set this field to assert that the request path matches. Path string + // Set this field to assert that the request URL querystring matches. + Query *url.Values // Set this field to assert that the request body matches. In json.RawMessage } @@ -34,11 +37,14 @@ func (rt *RoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { if rt.Status == 0 { rt.Status = http.StatusOK } + if rt.Method != "" { + require.Equal(rt.T, rt.Method, r.Method) + } if rt.Path != "" { require.Equal(rt.T, rt.Path, r.URL.Path) } - if rt.Method != "" { - require.Equal(rt.T, rt.Method, r.Method) + if rt.Query != nil { + require.Equal(rt.T, rt.Query.Encode(), r.URL.Query().Encode()) } if rt.In != nil { body, err := io.ReadAll(r.Body) diff --git a/client.go b/client.go new file mode 100644 index 00000000..1537cf88 --- /dev/null +++ b/client.go @@ -0,0 +1,20 @@ +package clerk + +type Client struct { + APIResource + Object string `json:"object"` + ID string `json:"id"` + LastActiveSessionID *string `json:"last_active_session_id"` + SignInID *string `json:"sign_in_id"` + SignUpID *string `json:"sign_up_id"` + SessionIDs []string `json:"session_ids"` + Sessions []*Session `json:"sessions"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +} + +type ClientList struct { + APIResource + Clients []*Client `json:"data"` + TotalCount int64 `json:"total_count"` +} diff --git a/client/api.go b/client/api.go new file mode 100644 index 00000000..54c6551b --- /dev/null +++ b/client/api.go @@ -0,0 +1,31 @@ +// Code generated by "gen"; DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. +// Last generated at 2024-02-07 13:46:28.207158003 +0000 UTC +package client + +import ( + "context" + + "github.com/clerk/clerk-sdk-go/v2" +) + +// Get retrieves the client specified by ID. +func Get(ctx context.Context, id string) (*clerk.Client, error) { + return getClient().Get(ctx, id) +} + +// Verify verifies the Client in the provided JWT. +func Verify(ctx context.Context, params *VerifyParams) (*clerk.Client, error) { + return getClient().Verify(ctx, params) +} + +// List returns a list of all the clients.//// Deprecated: The operation is deprecated and will be removed in// future versions. +func List(ctx context.Context, params *ListParams) (*clerk.ClientList, error) { + return getClient().List(ctx, params) +} + +func getClient() *Client { + return &Client{ + Backend: clerk.GetBackend(), + } +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 00000000..5c91f0ef --- /dev/null +++ b/client/client.go @@ -0,0 +1,81 @@ +// Package client provides the Client API. +package client + +import ( + "context" + "net/http" + "net/url" + + "github.com/clerk/clerk-sdk-go/v2" +) + +//go:generate go run ../cmd/gen/main.go + +const path = "/clients" + +// Client is used to invoke the Client API. +// This is an API client for interacting with Clerk Client resources. +type Client struct { + Backend clerk.Backend +} + +type ClientConfig struct { + clerk.BackendConfig +} + +func NewClient(config *ClientConfig) *Client { + return &Client{ + Backend: clerk.NewBackend(&config.BackendConfig), + } +} + +// Get retrieves the client specified by ID. +func (c *Client) Get(ctx context.Context, id string) (*clerk.Client, error) { + path, err := clerk.JoinPath(path, id) + if err != nil { + return nil, err + } + req := clerk.NewAPIRequest(http.MethodGet, path) + client := &clerk.Client{} + err = c.Backend.Call(ctx, req, client) + return client, err +} + +type VerifyParams struct { + clerk.APIParams + Token *string `json:"token,omitempty"` +} + +// Verify verifies the Client in the provided JWT. +func (c *Client) Verify(ctx context.Context, params *VerifyParams) (*clerk.Client, error) { + path, err := clerk.JoinPath(path, "/verify") + if err != nil { + return nil, err + } + req := clerk.NewAPIRequest(http.MethodPost, path) + req.SetParams(params) + client := &clerk.Client{} + err = c.Backend.Call(ctx, req, client) + return client, err +} + +type ListParams struct { + clerk.APIParams + clerk.ListParams +} + +func (params *ListParams) ToQuery() url.Values { + return params.ListParams.ToQuery() +} + +// List returns a list of all the clients. +// +// Deprecated: The operation is deprecated and will be removed in +// future versions. +func (c *Client) List(ctx context.Context, params *ListParams) (*clerk.ClientList, error) { + req := clerk.NewAPIRequest(http.MethodGet, path) + req.SetParams(params) + list := &clerk.ClientList{} + err := c.Backend.Call(ctx, req, list) + return list, err +} diff --git a/client/client_test.go b/client/client_test.go new file mode 100644 index 00000000..91091f45 --- /dev/null +++ b/client/client_test.go @@ -0,0 +1,84 @@ +package client + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "testing" + + "github.com/clerk/clerk-sdk-go/v2" + "github.com/clerk/clerk-sdk-go/v2/clerktest" + "github.com/stretchr/testify/require" +) + +func TestClientClientGet(t *testing.T) { + t.Parallel() + id := "client_123" + config := &ClientConfig{} + config.HTTPClient = &http.Client{ + Transport: &clerktest.RoundTripper{ + T: t, + Out: json.RawMessage(fmt.Sprintf(`{"id":"%s"}`, id)), + Method: http.MethodGet, + Path: "/v1/clients/" + id, + }, + } + c := NewClient(config) + client, err := c.Get(context.Background(), id) + require.NoError(t, err) + require.Equal(t, id, client.ID) +} + +func TestClientClientVerify(t *testing.T) { + t.Parallel() + id := "client_123" + token := "the-token" + config := &ClientConfig{} + config.HTTPClient = &http.Client{ + Transport: &clerktest.RoundTripper{ + T: t, + In: json.RawMessage(fmt.Sprintf(`{"token":"%s"}`, token)), + Out: json.RawMessage(fmt.Sprintf(`{"id":"%s"}`, id)), + Method: http.MethodPost, + Path: "/v1/clients/verify", + }, + } + c := NewClient(config) + client, err := c.Verify(context.Background(), &VerifyParams{ + Token: clerk.String("the-token"), + }) + require.NoError(t, err) + require.Equal(t, id, client.ID) +} + +func TestClientClientList(t *testing.T) { + t.Parallel() + config := &ClientConfig{} + config.HTTPClient = &http.Client{ + Transport: &clerktest.RoundTripper{ + T: t, + Out: json.RawMessage(`{ + "data": [{"id":"client_123","last_active_session_id":"sess_123"}], + "total_count": 1 +}`), + Method: http.MethodGet, + Path: "/v1/clients", + Query: &url.Values{ + "limit": []string{"1"}, + "offset": []string{"2"}, + }, + }, + } + c := NewClient(config) + params := &ListParams{} + params.Limit = clerk.Int64(1) + params.Offset = clerk.Int64(2) + list, err := c.List(context.Background(), params) + require.NoError(t, err) + require.Equal(t, int64(1), list.TotalCount) + require.Equal(t, 1, len(list.Clients)) + require.Equal(t, "client_123", list.Clients[0].ID) + require.Equal(t, "sess_123", *list.Clients[0].LastActiveSessionID) +} diff --git a/session.go b/session.go new file mode 100644 index 00000000..23684e54 --- /dev/null +++ b/session.go @@ -0,0 +1,19 @@ +package clerk + +import "encoding/json" + +type Session struct { + APIResource + Object string `json:"object"` + ID string `json:"id"` + ClientID string `json:"client_id"` + UserID string `json:"user_id"` + Status string `json:"status"` + LastActiveOrganizationID string `json:"last_active_organization_id,omitempty"` + Actor json.RawMessage `json:"actor,omitempty"` + LastActiveAt int64 `json:"last_active_at"` + ExpireAt int64 `json:"expire_at"` + AbandonAt int64 `json:"abandon_at"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +}