Skip to content

Commit

Permalink
feat: API operations for JWT Templates (#225)
Browse files Browse the repository at this point in the history
Added support for the JWT Templates API with Create, Get, Update, Delete
and List operations.
  • Loading branch information
gkats authored Feb 8, 2024
1 parent 0954e0f commit 7d5a78d
Show file tree
Hide file tree
Showing 4 changed files with 350 additions and 0 deletions.
23 changes: 23 additions & 0 deletions jwt_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package clerk

import "encoding/json"

type JWTTemplate struct {
APIResource
Object string `json:"object"`
ID string `json:"id"`
Name string `json:"name"`
Claims json.RawMessage `json:"claims"`
Lifetime int64 `json:"lifetime"`
AllowedClockSkew int64 `json:"allowed_clock_skew"`
CustomSigningKey bool `json:"custom_signing_key"`
SigningAlgorithm string `json:"signing_algorithm"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}

type JWTTemplateList struct {
APIResource
JWTTemplates []*JWTTemplate `json:"data"`
TotalCount int64 `json:"total_count"`
}
41 changes: 41 additions & 0 deletions jwttemplate/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

111 changes: 111 additions & 0 deletions jwttemplate/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Package jwttemplate provides the JWT Templates API.
package jwttemplate

import (
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/clerk/clerk-sdk-go/v2"
)

//go:generate go run ../cmd/gen/main.go

const path = "/jwt_templates"

// Client is used to invoke the JWT Templates API.
type Client struct {
Backend clerk.Backend
}

type ClientConfig struct {
clerk.BackendConfig
}

func NewClient(config *ClientConfig) *Client {
return &Client{
Backend: clerk.NewBackend(&config.BackendConfig),
}
}

type CreateParams struct {
clerk.APIParams
Name *string `json:"name,omitempty"`
Claims json.RawMessage `json:"claims,omitempty"`
Lifetime *int64 `json:"lifetime,omitempty"`
AllowedClockSkew *int64 `json:"allowed_clock_skew,omitempty"`
CustomSigningKey *bool `json:"custom_signing_key,omitempty"`
SigningKey *string `json:"signing_key,omitempty"`
SigningAlgorithm *string `json:"signing_algorithm,omitempty"`
}

// Create creates a new JWT template.
func (c *Client) Create(ctx context.Context, params *CreateParams) (*clerk.JWTTemplate, error) {
req := clerk.NewAPIRequest(http.MethodPost, path)
req.SetParams(params)
template := &clerk.JWTTemplate{}
err := c.Backend.Call(ctx, req, template)
return template, err
}

// Get returns details about a JWT template.
func (c *Client) Get(ctx context.Context, id string) (*clerk.JWTTemplate, error) {
path, err := clerk.JoinPath(path, id)
if err != nil {
return nil, err
}
req := clerk.NewAPIRequest(http.MethodGet, path)
template := &clerk.JWTTemplate{}
err = c.Backend.Call(ctx, req, template)
return template, err
}

type UpdateParams struct {
clerk.APIParams
Name *string `json:"name,omitempty"`
Claims json.RawMessage `json:"claims,omitempty"`
Lifetime *int64 `json:"lifetime,omitempty"`
AllowedClockSkew *int64 `json:"allowed_clock_skew,omitempty"`
CustomSigningKey *bool `json:"custom_signing_key,omitempty"`
SigningKey *string `json:"signing_key,omitempty"`
SigningAlgorithm *string `json:"signing_algorithm,omitempty"`
}

// Update updates the JWT template specified by id.
func (c *Client) Update(ctx context.Context, id string, params *UpdateParams) (*clerk.JWTTemplate, error) {
path, err := clerk.JoinPath(path, id)
if err != nil {
return nil, err
}
req := clerk.NewAPIRequest(http.MethodPatch, path)
req.SetParams(params)
template := &clerk.JWTTemplate{}
err = c.Backend.Call(ctx, req, template)
return template, err
}

// Delete deletes a JWT template.
func (c *Client) Delete(ctx context.Context, id string) (*clerk.DeletedResource, error) {
path, err := clerk.JoinPath(path, id)
if err != nil {
return nil, err
}
req := clerk.NewAPIRequest(http.MethodDelete, path)
template := &clerk.DeletedResource{}
err = c.Backend.Call(ctx, req, template)
return template, err
}

type ListParams struct {
clerk.APIParams
}

// List returns a list of JWT templates.
func (c *Client) List(ctx context.Context, params *ListParams) (*clerk.JWTTemplateList, error) {
req := clerk.NewAPIRequest(http.MethodGet, fmt.Sprintf("%s?paginated=true", path))
req.SetParams(params)
list := &clerk.JWTTemplateList{}
err := c.Backend.Call(ctx, req, list)
return list, err
}
175 changes: 175 additions & 0 deletions jwttemplate/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package jwttemplate

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 TestJWTTemplateClientCreate(t *testing.T) {
t.Parallel()
name := "the-name"
id := "jtmpl_123"
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
In: json.RawMessage(fmt.Sprintf(`{"name":"%s"}`, name)),
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","name":"%s"}`, id, name)),
Method: http.MethodPost,
Path: "/v1/jwt_templates",
},
}
client := NewClient(config)
jwtTemplate, err := client.Create(context.Background(), &CreateParams{
Name: clerk.String(name),
})
require.NoError(t, err)
require.Equal(t, id, jwtTemplate.ID)
require.Equal(t, name, jwtTemplate.Name)
}

func TestJWTTemplateClientCreate_Error(t *testing.T) {
t.Parallel()
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Status: http.StatusBadRequest,
Out: json.RawMessage(`{
"errors":[{
"code":"create-error-code"
}],
"clerk_trace_id":"create-trace-id"
}`),
},
}
client := NewClient(config)
_, err := client.Create(context.Background(), &CreateParams{})
require.Error(t, err)
apiErr, ok := err.(*clerk.APIErrorResponse)
require.True(t, ok)
require.Equal(t, "create-trace-id", apiErr.TraceID)
require.Equal(t, 1, len(apiErr.Errors))
require.Equal(t, "create-error-code", apiErr.Errors[0].Code)
}

func TestJWTTemplateClientGet(t *testing.T) {
t.Parallel()
id := "jtmpl_123"
name := "the-name"
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","name":"%s"}`, id, name)),
Method: http.MethodGet,
Path: "/v1/jwt_templates/" + id,
},
}
client := NewClient(config)
jwtTemplate, err := client.Get(context.Background(), id)
require.NoError(t, err)
require.Equal(t, id, jwtTemplate.ID)
require.Equal(t, name, jwtTemplate.Name)
}

func TestJWTTemplateClientUpdate(t *testing.T) {
t.Parallel()
id := "jtmpl_123"
name := "the-name"
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
In: json.RawMessage(fmt.Sprintf(`{"name":"%s"}`, name)),
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","name":"%s"}`, id, name)),
Method: http.MethodPatch,
Path: "/v1/jwt_templates/" + id,
},
}
client := NewClient(config)
jwtTemplate, err := client.Update(context.Background(), id, &UpdateParams{
Name: clerk.String(name),
})
require.NoError(t, err)
require.Equal(t, id, jwtTemplate.ID)
require.Equal(t, name, jwtTemplate.Name)
}

func TestJWTTemplateClientUpdate_Error(t *testing.T) {
t.Parallel()
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Status: http.StatusBadRequest,
Out: json.RawMessage(`{
"errors":[{
"code":"update-error-code"
}],
"clerk_trace_id":"update-trace-id"
}`),
},
}
client := NewClient(config)
_, err := client.Update(context.Background(), "jtmpl_123", &UpdateParams{})
require.Error(t, err)
apiErr, ok := err.(*clerk.APIErrorResponse)
require.True(t, ok)
require.Equal(t, "update-trace-id", apiErr.TraceID)
require.Equal(t, 1, len(apiErr.Errors))
require.Equal(t, "update-error-code", apiErr.Errors[0].Code)
}

func TestJWTTemplateClientDelete(t *testing.T) {
t.Parallel()
id := "jtmpl_456"
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","deleted":true}`, id)),
Method: http.MethodDelete,
Path: "/v1/jwt_templates/" + id,
},
}
client := NewClient(config)
jwtTemplate, err := client.Delete(context.Background(), id)
require.NoError(t, err)
require.Equal(t, id, jwtTemplate.ID)
require.True(t, jwtTemplate.Deleted)
}

func TestJWTTemplateClientList(t *testing.T) {
t.Parallel()
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Out: json.RawMessage(`{
"data": [{"id":"jtmpl_123","name":"the-name"}],
"total_count": 1
}`),
Method: http.MethodGet,
Path: "/v1/jwt_templates",
Query: &url.Values{
"paginated": []string{"true"},
},
},
}
client := NewClient(config)
list, err := client.List(context.Background(), &ListParams{})
require.NoError(t, err)
require.Equal(t, int64(1), list.TotalCount)
require.Equal(t, 1, len(list.JWTTemplates))
require.Equal(t, "jtmpl_123", list.JWTTemplates[0].ID)
require.Equal(t, "the-name", list.JWTTemplates[0].Name)
}

0 comments on commit 7d5a78d

Please sign in to comment.