-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Groundwork for v2 #206
Groundwork for v2 #206
Conversation
Removed all files to prepare for a v2 rewrite.
e9c8f01
to
1e25cbb
Compare
clerk.go
Outdated
) | ||
|
||
// SecretKey is the Clerk secret key. Configured on a package level. | ||
var SecretKey string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ I don't think the secret key should be exported. Perhaps now is a good opportunity to move away from this since it is a breaking change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@georgepsarakis Can you think of a problem with exporting the SecretKey
on the package level?
The benefit is that you can set your key with a simple API.
clerk.SecretKey = "sk_live_123"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the variable non-exported and we now offer a clerk.SetKey("sk_live_123")
method to configure your API key.
clerk.go
Outdated
const defaultHTTPTimeout = 5 * time.Second | ||
|
||
// The default HTTP client used for communication with the Clerk API. | ||
var httpClient = &http.Client{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Perhaps:
var httpClient = &http.Client{ | |
var defaultHTTPClient = &http.Client{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed. 😄
} | ||
|
||
// The active Backend | ||
var backend api |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ I'm not sure I understand the use of these globals, along with the Get/SetBackend
functions. I would maybe expect that a NewAPIClient
method (if I understand the parity with the Backend
interface here), returns a fully isolated client instance. Any chance we need to simplify some aspects here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends.
Having a "singleton" global API client allows for two things:
- Simple API for operations
clerk.SecretKey = "sk_live_123"
dmn, err := domain.Create(ctx, &DomainParams{})
- Ability to stub out the client for tests
clerk.SetBackend(clerk.NewBackend(&clerk.BackendConfig{
HTTPClient: myCustomClient,
}))
domain.Create(ctx, &clerk.DomainParams{})
I'm facing the same dilemma as you. Is the global singleton-like backend worth the trouble? Will it actually prove flexible or not? I toyed around with different approaches, but DX-wise, I believe nothing beats the API described above.
How would the alternative look like?
domain.NewClient(&clerk.BackendConfig{}).Create(ctx, &clerk.DomainParams{})
Or I imagine in your main.go file
package main
type Server struct {
domainClient *domain.Client
organizationClient *organization.Client
}
func main() {
// Instantiate your clients and your server struct to ListenAndServe
clerkConfig := &clerk.BackendConfig{
HTTPClient: myCustomClient,
}
srv := &Server{
domainClient: domain.NewClient(clerkConfig),
organizationClient: organization.NewClient(clerkConfig),
}
// routes, handlers, and ListenAndServe
srv.Start()
}
// and then in your handler
func (srv *Server) CreateDomains(w, r) {
dmn, err := srv.domainClient.Create(ctx, &clerk.DomainParams{})
}
Comparing this solution, to the dmn, err := domain.Create()
example above, there's a clear DX benefit in my eyes.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ability to stub out the client for tests
The use of a global variable here seems to be breaking test isolation, if tests are running in parallel. So if I understand correctly we may not allow dependency injection 🤔 ?
I think you can avoid the (broader) use of globals with defining an explicit setter for a default backend and provide constructors for dependency injection. I imagine the API being something like:
package clerk
type Backend struct {
httpClient *http.Client
}
var defaultBackend = &Backend{}
func SetDefaultBackend(cfg *BackendConfig) {
// Resembles `SetBackend` now but mutates an existing struct
defaultBackend.httpClient = cfg.HTTPClient
}
func DefaultBackend() *Backend {
return defaultBackend
}
type DomainsClient struct {
backend *Backend
}
func NewDomainsClient(backend *Backend) *DomainsClient {}
var Domains = struct {
backend *Backend
}{backend: defaultBackend}
func (d *Domains) Create(ctx context.Context, params *CreateDomainParams) (Domain, error) {}
On the user's side:
package main
func main() {
// or this can happen on the user's package-level init()
clerk.SetDefaultBackend(...)
}
func CreateDomains(ctx context.Context, name string) (..., error) {
domain, err := clerk.Domains.Create(ctx, &clerk.DomainParams{Name: name})
}
Just an idea, I'm not sure what the exact end-user API needs to be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved the discussion offline. We'll go ahead with the current design until there's more strong evidence towards change.
51f26cb
to
df246fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏 Approving since this is foundational work in order to move things forward! There seems to be a failure for Go 1.17 that might be worth looking into.
- name: Run linter | ||
uses: golangci/golangci-lint-action@v3 | ||
test: | ||
name: "Test: go v${{ matrix.go-version }}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Just a note that you may want to retain the CI required check name. If I understand correctly all CI checks are optional now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really ❤️ where this is going! Great work @gkats .
@georgepsarakis raised some very valid concerns/questions. Other than that, looks great to me!
|
||
const ( | ||
sdkVersion string = "v2.0.0" | ||
clerkAPIVersion string = "v1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is not needed anymore, given our plan for API versioning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 When we're done with API versioning I'll revisit. Leaving this mostly as a placeholder for now.
|
||
const ( | ||
// APIURL is the base URL for the Clerk API. | ||
APIURL string = "https://api.clerk.com" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it's the Go convention, but APIURL
looks sooo strange!
df246fa
to
2ed2576
Compare
Added core types, methods and interfaces for building API operations. The package provides a basic Backend that can communicate with the Clerk API. The Backend can handle APIRequest requests and APIResponse responses. Types are also provided for API resources and parameters, as well as expected errors.
Added a new CI workflow for Github Actions that will vet, and lint the code and run the test suite. Linting is done with golangci-lint. Tests are run against all Go versions from 1.19 onwards.
2ed2576
to
c33a952
Compare
* chore: Fresh start Removed all files to prepare for a v2 rewrite. * feat: Base for implementing API operations Added core types, methods and interfaces for building API operations. The package provides a basic Backend that can communicate with the Clerk API. The Backend can handle APIRequest requests and APIResponse responses. Types are also provided for API resources and parameters, as well as expected errors. * feat: Add CI workflow Added a new CI workflow for Github Actions that will vet, and lint the code and run the test suite. Linting is done with golangci-lint. Tests are run against all Go versions from 1.19 onwards.
* chore: Fresh start Removed all files to prepare for a v2 rewrite. * feat: Base for implementing API operations Added core types, methods and interfaces for building API operations. The package provides a basic Backend that can communicate with the Clerk API. The Backend can handle APIRequest requests and APIResponse responses. Types are also provided for API resources and parameters, as well as expected errors. * feat: Add CI workflow Added a new CI workflow for Github Actions that will vet, and lint the code and run the test suite. Linting is done with golangci-lint. Tests are run against all Go versions from 1.19 onwards.
Type of change
Description
🎉 Kicking off the v2 rewrite of our Go SDK. 🎉
The work here is split into three commits. It might be easier to review commit by commit, because there's a lot of changed files.
We're moving into a different direction with our SDK. This PR includes the core tools for implementing all API operations.
We have three basic interfaces in our SDK.
Along with these interfaces we have some basic types that describe core API resources. These are
A default Backend implementation is provided but not exported.
Using the above types, implementing an API operation should be easy. Take a look at the tests (clerk_test.go) for a few examples of how we would write API operations.
Finally, consuming the API operation that we implemented above would look like this
As you might have guessed, the API and implementation is based on Stripe's Go SDK