Skip to content

Commit

Permalink
feat: Email Addresses API (#224)
Browse files Browse the repository at this point in the history
Added support for the Email Addresses API operations Create, Read,
Update and Delete.
  • Loading branch information
gkats authored Feb 7, 2024
1 parent 3550faf commit 0954e0f
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 0 deletions.
5 changes: 5 additions & 0 deletions clerk.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,8 @@ func String(v string) *string {
func Int64(v int64) *int64 {
return &v
}

// Bool returns a pointer to the provided bool value.
func Bool(v bool) *bool {
return &v
}
29 changes: 29 additions & 0 deletions email_address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package clerk

import "encoding/json"

type EmailAddress struct {
APIResource
ID string `json:"id"`
Object string `json:"object"`
EmailAddress string `json:"email_address"`
Reserved bool `json:"reserved"`
Verification *Verification `json:"verification"`
LinkedTo []*LinkedIdentification `json:"linked_to"`
}

type Verification struct {
Status string `json:"status"`
Strategy string `json:"strategy"`
Attempts *int64 `json:"attempts"`
ExpireAt *int64 `json:"expire_at"`
VerifiedAtClient string `json:"verified_at_client,omitempty"`
Nonce *string `json:"nonce,omitempty"`
ExternalVerificationRedirectURL *string `json:"external_verification_redirect_url,omitempty"`
Error json.RawMessage `json:"error,omitempty"`
}

type LinkedIdentification struct {
ID string `json:"id"`
Type string `json:"type"`
}
36 changes: 36 additions & 0 deletions emailaddress/api.go

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

88 changes: 88 additions & 0 deletions emailaddress/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Package emailaddress provides the Email Addresses API.
package emailaddress

import (
"context"
"net/http"

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

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

const path = "/email_addresses"

// Client is used to invoke the Email Addresses 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
UserID *string `json:"user_id,omitempty"`
EmailAddress *string `json:"email_address,omitempty"`
Verified *bool `json:"verified,omitempty"`
Primary *bool `json:"primary,omitempty"`
}

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

// Get retrieves an email address.
func (c *Client) Get(ctx context.Context, id string) (*clerk.EmailAddress, error) {
path, err := clerk.JoinPath(path, id)
if err != nil {
return nil, err
}
req := clerk.NewAPIRequest(http.MethodGet, path)
emailAddress := &clerk.EmailAddress{}
err = c.Backend.Call(ctx, req, emailAddress)
return emailAddress, err
}

type UpdateParams struct {
clerk.APIParams
Verified *bool `json:"verified,omitempty"`
Primary *bool `json:"primary,omitempty"`
}

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

// Delete deletes an email address.
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)
emailAddress := &clerk.DeletedResource{}
err = c.Backend.Call(ctx, req, emailAddress)
return emailAddress, err
}
149 changes: 149 additions & 0 deletions emailaddress/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package emailaddress

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

"github.com/clerk/clerk-sdk-go/v2"
"github.com/clerk/clerk-sdk-go/v2/clerktest"
"github.com/stretchr/testify/require"
)

func TestEmailAddressClientCreate(t *testing.T) {
t.Parallel()
email := "[email protected]"
userID := "user_123"
id := "idn_123"
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
In: json.RawMessage(fmt.Sprintf(`{"email_address":"%s","user_id":"%s","verified":false}`, email, userID)),
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","email_address":"%s"}`, id, email)),
Method: http.MethodPost,
Path: "/v1/email_addresses",
},
}
client := NewClient(config)
emailAddress, err := client.Create(context.Background(), &CreateParams{
UserID: clerk.String(userID),
EmailAddress: clerk.String(email),
Verified: clerk.Bool(false),
})
require.NoError(t, err)
require.Equal(t, id, emailAddress.ID)
require.Equal(t, email, emailAddress.EmailAddress)
}

func TestEmailAddressClientCreate_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 TestEmailAddressClientUpdate(t *testing.T) {
t.Parallel()
id := "idn_123"
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
In: json.RawMessage(`{"verified":true}`),
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","verification":{"status":"verified"}}`, id)),
Method: http.MethodPatch,
Path: "/v1/email_addresses/" + id,
},
}
client := NewClient(config)
emailAddress, err := client.Update(context.Background(), "idn_123", &UpdateParams{
Verified: clerk.Bool(true),
})
require.NoError(t, err)
require.Equal(t, id, emailAddress.ID)
require.Equal(t, "verified", emailAddress.Verification.Status)
}

func TestEmailAddressClientUpdate_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(), "idn_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 TestEmailAddressClientGet(t *testing.T) {
t.Parallel()
id := "idn_123"
config := &ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","verification":{"status":"verified"}}`, id)),
Method: http.MethodGet,
Path: "/v1/email_addresses/" + id,
},
}
client := NewClient(config)
emailAddress, err := client.Get(context.Background(), id)
require.NoError(t, err)
require.Equal(t, id, emailAddress.ID)
require.Equal(t, "verified", emailAddress.Verification.Status)
}

func TestEmailAddressClientDelete(t *testing.T) {
t.Parallel()
id := "idn_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/email_addresses/" + id,
},
}
client := NewClient(config)
emailAddress, err := client.Delete(context.Background(), id)
require.NoError(t, err)
require.Equal(t, id, emailAddress.ID)
require.True(t, emailAddress.Deleted)
}

0 comments on commit 0954e0f

Please sign in to comment.