Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 469
chore(backend,nextjs,clerk-sdk-node): Drop legacy return response in BAPI responses#2126
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| --- | ||
| '@clerk/clerk-sdk-node': major | ||
| '@clerk/backend': major | ||
| '@clerk/nextjs': major | ||
| --- | ||
| Change the response payload of Backend API requests to return `{ data, errors }` instead of return the data and throwing on error response. | ||
| Code example to keep the same behavior: | ||
| ```typescript | ||
| import { users } from '@clerk/backend'; | ||
| import { ClerkAPIResponseError } from '@clerk/shared/error'; | ||
| const { data, errors, clerkTraceId, status, statusText } = await users.getUser('user_deadbeef'); | ||
| if(errors){ | ||
| throw new ClerkAPIResponseError(statusText, { data: errors, status, clerkTraceId }); | ||
| } | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -4,6 +4,7 @@ import sinon from 'sinon'; | ||
| import emailJson from '../fixtures/responses/email.json'; | ||
| import userJson from '../fixtures/responses/user.json'; | ||
| import runtime from '../runtime'; | ||
| import { assertErrorResponse, assertResponse } from '../util/assertResponse'; | ||
| import { jsonError, jsonNotOk, jsonOk } from '../util/mockFetch'; | ||
| import { createBackendApiClient } from './factory'; | ||
| @@ -26,22 +27,17 @@ export default (QUnit: QUnit) => { | ||
| fakeFetch = sinon.stub(runtime, 'fetch'); | ||
| fakeFetch.onCall(0).returns(jsonOk(userJson)); | ||
| const payload = await apiClient.users.getUser('user_deadbeef'); | ||
| const response = await apiClient.users.getUser('user_deadbeef'); | ||
| if (!payload) { | ||
| // eslint-disable-next-line qunit/no-conditional-assertions | ||
| assert.false(true, 'This assertion should never fail. We need to check for payload to make TS happy.'); | ||
| // eslint-disable-next-line qunit/no-early-return | ||
| return; | ||
| } | ||
ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
| ||
| assertResponse(assert, response); | ||
| const { data: payload } = response; | ||
| assert.equal(payload.firstName, 'John'); | ||
| assert.equal(payload.lastName, 'Doe'); | ||
| assert.equal(payload.emailAddresses[0].emailAddress, 'john.doe@clerk.test'); | ||
| assert.equal(payload.phoneNumbers[0].phoneNumber, '+311-555-2368'); | ||
| assert.equal(payload.externalAccounts[0].emailAddress, 'john.doe@clerk.test'); | ||
| assert.equal(payload.publicMetadata.zodiac_sign, 'leo'); | ||
| // assert.equal(payload.errors, null); | ||
| assert.ok( | ||
| fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { | ||
| @@ -59,22 +55,16 @@ export default (QUnit: QUnit) => { | ||
| fakeFetch = sinon.stub(runtime, 'fetch'); | ||
| fakeFetch.onCall(0).returns(jsonOk([userJson])); | ||
| const payload = await apiClient.users.getUserList({ offset: 2, limit: 5 }); | ||
| if (!payload) { | ||
| // eslint-disable-next-line qunit/no-conditional-assertions | ||
| assert.false(true, 'This assertion should never fail. We need to check for payload to make TS happy.'); | ||
| // eslint-disable-next-line qunit/no-early-return | ||
| return; | ||
| } | ||
| const response = await apiClient.users.getUserList({ offset: 2, limit: 5 }); | ||
| assertResponse(assert, response); | ||
| const { data: payload } = response; | ||
| assert.equal(payload[0].firstName, 'John'); | ||
| assert.equal(payload[0].lastName, 'Doe'); | ||
| assert.equal(payload[0].emailAddresses[0].emailAddress, 'john.doe@clerk.test'); | ||
| assert.equal(payload[0].phoneNumbers[0].phoneNumber, '+311-555-2368'); | ||
| assert.equal(payload[0].externalAccounts[0].emailAddress, 'john.doe@clerk.test'); | ||
| assert.equal(payload[0].publicMetadata.zodiac_sign, 'leo'); | ||
| // assert.equal(payload.errors, null); | ||
| assert.ok( | ||
| fakeFetch.calledOnceWith('https://api.clerk.test/v1/users?offset=2&limit=5', { | ||
| @@ -100,14 +90,10 @@ export default (QUnit: QUnit) => { | ||
| }; | ||
| const requestBody = | ||
| '{"from_email_name":"foobar123","email_address_id":"test@test.dev","body":"this is a test","subject":"this is a test"}'; | ||
| const payload = await apiClient.emails.createEmail(body); | ||
| if (!payload) { | ||
| // eslint-disable-next-line qunit/no-conditional-assertions | ||
| assert.false(true, 'This assertion should never fail. We need to check for payload to make TS happy.'); | ||
| // eslint-disable-next-line qunit/no-early-return | ||
| return; | ||
| } | ||
| const response = await apiClient.emails.createEmail(body); | ||
| assertResponse(assert, response); | ||
| const { data: payload } = response; | ||
| assert.equal(JSON.stringify(payload.data), '{}'); | ||
| assert.equal(payload.id, 'ema_2PHa2N3bS7D6NPPQ5mpHEg0waZQ'); | ||
| @@ -126,15 +112,19 @@ export default (QUnit: QUnit) => { | ||
| test('executes a successful backend API request to create a new resource', async assert => { | ||
| fakeFetch = sinon.stub(runtime, 'fetch'); | ||
| fakeFetch.onCall(0).returns(jsonOk([userJson])); | ||
| fakeFetch.onCall(0).returns(jsonOk(userJson)); | ||
| await apiClient.users.createUser({ | ||
| const response = await apiClient.users.createUser({ | ||
| firstName: 'John', | ||
| lastName: 'Doe', | ||
| publicMetadata: { | ||
| star_sign: 'Leon', | ||
| }, | ||
| }); | ||
| assertResponse(assert, response); | ||
| const { data: payload } = response; | ||
| assert.equal(payload.firstName, 'John'); | ||
| assert.ok( | ||
| fakeFetch.calledOnceWith('https://api.clerk.test/v1/users', { | ||
| @@ -161,14 +151,13 @@ export default (QUnit: QUnit) => { | ||
| fakeFetch = sinon.stub(runtime, 'fetch'); | ||
| fakeFetch.onCall(0).returns(jsonNotOk({ errors: [mockErrorPayload], clerk_trace_id: traceId })); | ||
| try { | ||
| await apiClient.users.getUser('user_deadbeef'); | ||
| } catch (e: any) { | ||
| assert.equal(e.clerkTraceId, traceId); | ||
| assert.true(e.clerkError); | ||
| assert.equal(e.status, 422); | ||
| assert.equal(e.errors[0].code, 'whatever_error'); | ||
| } | ||
| const response = await apiClient.users.getUser('user_deadbeef'); | ||
| assertErrorResponse(assert, response); | ||
| assert.equal(response.clerkTraceId, traceId); | ||
| assert.equal(response.status, 422); | ||
| assert.equal(response.statusText, '422'); | ||
| assert.equal(response.errors[0].code, 'whatever_error'); | ||
| assert.ok( | ||
| fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { | ||
| @@ -186,13 +175,12 @@ export default (QUnit: QUnit) => { | ||
| fakeFetch = sinon.stub(runtime, 'fetch'); | ||
| fakeFetch.onCall(0).returns(jsonError({ errors: [] })); | ||
| try { | ||
| await apiClient.users.getUser('user_deadbeef'); | ||
| } catch (e: any) { | ||
| assert.true(e.clerkError); | ||
| assert.equal(e.status, 500); | ||
| assert.equal(e.clerkTraceId, 'mock_cf_ray'); | ||
| } | ||
| const response = await apiClient.users.getUser('user_deadbeef'); | ||
| assertErrorResponse(assert, response); | ||
| assert.equal(response.status, 500); | ||
| assert.equal(response.statusText, '500'); | ||
| assert.equal(response.clerkTraceId, 'mock_cf_ray'); | ||
| assert.ok( | ||
| fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| type ApiResponse<T> = { data: T | null; errors: null | any[] }; | ||
| type SuccessApiResponse<T> = { data: T; errors: null }; | ||
| type ErrorApiResponse = { data: null; errors: any[]; clerkTraceId: string; status: number; statusText: string }; | ||
| export function assertResponse<T>(assert: Assert, resp: ApiResponse<T>): asserts resp is SuccessApiResponse<T> { | ||
| assert.equal(resp.errors, null); | ||
| } | ||
| export function assertErrorResponse<T>(assert: Assert, resp: ApiResponse<T>): asserts resp is ErrorApiResponse { | ||
| assert.notEqual(resp.errors, null); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,29 @@ | ||
| import { organizations, users } from '@clerk/clerk-sdk-node'; | ||
| console.log('Get user to create organization'); | ||
| const [creator] = await users.getUserList(); | ||
| const { data, errors } = await users.getUserList(); | ||
| if (errors) { | ||
| throw new Error(errors); | ||
| } | ||
| const creator = data[0]; | ||
| console.log('Create organization'); | ||
| const organization = await organizations.createOrganization({ | ||
| const { data: organization } = await organizations.createOrganization({ | ||
| name: 'test-organization', | ||
| createdBy: creator.id, | ||
| }); | ||
| console.log(organization); | ||
| console.log('Update organization metadata'); | ||
| const updatedOrganizationMetadata = | ||
| await organizations.updateOrganizationMetadata(organization.id, { | ||
| const { data: updatedOrganizationMetadata, errors: uomErrors } = await organizations.updateOrganizationMetadata( | ||
| organization.id, | ||
| { | ||
| publicMetadata: { test: 1 }, | ||
| }); | ||
| }, | ||
| ); | ||
| if (uomErrors) { | ||
| throw new Error(uomErrors); | ||
| } | ||
| console.log(updatedOrganizationMetadata); |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.