From 39301db1dd08e6196e35666ed8f9cb338befb92a Mon Sep 17 00:00:00 2001 From: Giannis Katsanos Date: Fri, 22 Mar 2024 11:52:29 +0200 Subject: [PATCH] feat: API versioning (#276) All requests set the Clerk-API-Version header to pin the SDK to a specific API version. The /v1/ part is no longer considered the API version. As such, it can be appended to the API base URL. --- clerk.go | 7 ++++--- clerk_test.go | 4 +++- http/middleware_test.go | 4 ++-- jwt/jwt_test.go | 10 +++++----- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/clerk.go b/clerk.go index 470267f2..1753a798 100644 --- a/clerk.go +++ b/clerk.go @@ -21,12 +21,12 @@ import ( const ( sdkVersion string = "v2.0.0" - clerkAPIVersion string = "v1" + clerkAPIVersion string = "2021-02-05" ) const ( // APIURL is the base URL for the Clerk API. - APIURL string = "https://api.clerk.com" + APIURL string = "https://api.clerk.com/v1" ) // The Clerk secret key. Configured on a package level. @@ -261,7 +261,7 @@ func (b *defaultBackend) Call(ctx context.Context, apiReq *APIRequest, setter Re } func (b *defaultBackend) newRequest(ctx context.Context, apiReq *APIRequest) (*http.Request, error) { - path, err := JoinPath(b.URL, clerkAPIVersion, apiReq.Path) + path, err := JoinPath(b.URL, apiReq.Path) if err != nil { return nil, err } @@ -272,6 +272,7 @@ func (b *defaultBackend) newRequest(ctx context.Context, apiReq *APIRequest) (*h req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", b.Key)) req.Header.Add("Content-Type", "application/json") req.Header.Add("User-Agent", fmt.Sprintf("clerk/clerk-sdk-go@%s", sdkVersion)) + req.Header.Add("Clerk-API-Version", clerkAPIVersion) req.Header.Add("X-Clerk-SDK", fmt.Sprintf("go/%s", sdkVersion)) b.CustomRequestHeaders.apply(req) req = req.WithContext(ctx) diff --git a/clerk_test.go b/clerk_test.go index e337026d..b76bbea3 100644 --- a/clerk_test.go +++ b/clerk_test.go @@ -180,13 +180,15 @@ func TestBackendCall_RequestHeaders(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, method, r.Method) - require.Equal(t, "/"+clerkAPIVersion+path, r.URL.Path) + require.Equal(t, path, r.URL.Path) // The client sets the Authorization header correctly. assert.Equal(t, fmt.Sprintf("Bearer %s", secretKey), r.Header.Get("Authorization")) // The client sets the User-Agent header. assert.Equal(t, fmt.Sprintf("clerk/clerk-sdk-go@%s", sdkVersion), r.Header.Get("User-Agent")) assert.Equal(t, "application/json", r.Header.Get("Content-Type")) + // The client sets the API version header. + assert.Equal(t, clerkAPIVersion, r.Header.Get("Clerk-API-Version")) // The client includes a custom header with the SDK version. assert.Equal(t, fmt.Sprintf("go/%s", sdkVersion), r.Header.Get("X-Clerk-SDK")) // Custom headers are added correctly. diff --git a/http/middleware_test.go b/http/middleware_test.go index 9886ea3b..5a205a84 100644 --- a/http/middleware_test.go +++ b/http/middleware_test.go @@ -71,10 +71,10 @@ func TestWithHeaderAuthorization_Caching(t *testing.T) { kid := "kid" clock := clockwork.NewFakeClockAt(time.Now().UTC()) - // Mock the Clerk API server. We expect requests to GET /v1/jwks. + // Mock the Clerk API server. We expect requests to GET /jwks. totalJWKSRequests := 0 clerkAPI := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/v1/jwks" && r.Method == http.MethodGet { + if r.URL.Path == "/jwks" && r.Method == http.MethodGet { // Count the number of requests to the JWKS endpoint totalJWKSRequests++ _, err := w.Write([]byte( diff --git a/jwt/jwt_test.go b/jwt/jwt_test.go index 05d084ca..13158f31 100644 --- a/jwt/jwt_test.go +++ b/jwt/jwt_test.go @@ -260,13 +260,13 @@ func TestVerify_CustomClaims(t *testing.T) { // TestVerify_UsesTheJWKSClient tests that when verifying a JWT if // you don't provide the JWK, the Verify method will make a request -// to GET /v1/jwks to fetch the JWK set. +// to GET /jwks to fetch the JWK set. func TestVerify_UsesTheJWKSClient(t *testing.T) { t.Parallel() kid := "kid" totalJWKSRequests := 0 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/v1/jwks" && r.Method == http.MethodGet { + if r.URL.Path == "/jwks" && r.Method == http.MethodGet { require.Equal(t, "custom client was used", r.Header.Get("X-Clerk-Application")) // Count the number of requests to the JWKS endpoint totalJWKSRequests++ @@ -312,7 +312,7 @@ func TestVerify_DefaultJWKSClient(t *testing.T) { kid := "kid" totalJWKSRequests := 0 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/v1/jwks" && r.Method == http.MethodGet { + if r.URL.Path == "/jwks" && r.Method == http.MethodGet { // Count the number of requests to the JWKS endpoint totalJWKSRequests++ _, err := w.Write([]byte( @@ -397,7 +397,7 @@ func TestGetJSONWebKey_DefaultJWKSClient(t *testing.T) { kid := "kid" totalJWKSRequests := 0 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/v1/jwks" && r.Method == http.MethodGet { + if r.URL.Path == "/jwks" && r.Method == http.MethodGet { // Count the number of requests to the JWKS endpoint totalJWKSRequests++ _, err := w.Write([]byte( @@ -429,7 +429,7 @@ func TestGetJSONWebKey_UsesTheJWKSClient(t *testing.T) { kid := "kid" totalJWKSRequests := 0 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/v1/jwks" && r.Method == http.MethodGet { + if r.URL.Path == "/jwks" && r.Method == http.MethodGet { require.Equal(t, "custom client was used", r.Header.Get("X-Clerk-Application")) // Count the number of requests to the JWKS endpoint totalJWKSRequests++