Skip to content
This repository has been archived by the owner on Mar 10, 2024. It is now read-only.

chore: Switching supaglue client over to the new openapi client #1954

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7dab210
feat: Download and generate openapi from outreach
tonyxiao Nov 16, 2023
2d57386
feat: Adding salesloft in addition to apollo
tonyxiao Nov 16, 2023
a4100a6
feat: Generate openapi spec for apollo also
tonyxiao Nov 17, 2023
792618b
chore: Use zod-openapi instead of zodios for refs support
tonyxiao Nov 17, 2023
e6168f3
chore: Suppress diffs for openapi files
tonyxiao Nov 17, 2023
2927e6b
chore: experiment with using @lilyrose2798/trpc-openapi to generate o…
tonyxiao Nov 17, 2023
a01093e
Revert "chore: experiment with using @lilyrose2798/trpc-openapi to ge…
tonyxiao Nov 17, 2023
fac1d55
chore: Rename .api to .client
tonyxiao Nov 17, 2023
cb6b294
chore: adding jsonOperation shorthand for createDocument
tonyxiao Nov 17, 2023
c863fc9
feat: Add createOpenapiClient that can handle refresh token and throw…
tonyxiao Nov 17, 2023
9ec73b3
feat: Introduce HTTPError class and untyped .request
tonyxiao Nov 18, 2023
3131867
feat: Outreach client refreshes token and apollo one attaches to quer…
tonyxiao Nov 18, 2023
fcda842
feat: Both Outreach and salesloft use oauth openapi client now
tonyxiao Nov 18, 2023
804766f
chore: Update yarn.lock
tonyxiao Nov 20, 2023
f7049c4
fix: Typing of wrapper client
tonyxiao Nov 20, 2023
76370de
chore: remove zodios and switching to use the new openapi client
tonyxiao Nov 20, 2023
f9cbcc9
chore: Switch to using json instead of yaml
tonyxiao Nov 20, 2023
ede7916
chore: Using serverUrl from openapi rather than hard-coding in client
tonyxiao Nov 20, 2023
b6af29a
chore: Add resolveJsonModule to all configs
tonyxiao Nov 20, 2023
ed54ee1
chore: Update prettier related deps
tonyxiao Nov 20, 2023
0a5c909
fix: prettier errors
tonyxiao Nov 20, 2023
f707e15
chore: Refactor the supaglue client to also use the new createOpenapi…
tonyxiao Nov 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@
"@typescript-eslint/no-misused-promises": ["warn", { "checksVoidReturn": false }],
"@typescript-eslint/consistent-type-imports": "error"
},
"ignorePatterns": ["node_modules/", "dist/", "coverage/", "/packages/schemas/gen/", "/packages/core/jest.config.js"]
"ignorePatterns": ["node_modules/", "dist/", "coverage/", "/packages/schemas/gen/", "/packages/core/jest.config.js", "*.openapi.gen.d.ts"]
}
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ openapi/**/openapi.bundle.json linguist-generated
*.example.json linguist-generated
/docs/docs/api/**/* linguist-generated
/docs/docs/api/introduction.md -linguist-generated
*.openapi.yaml linguist-generated
*.openapi.json linguist-generated
*.openapi.gen.d.ts linguist-generated
18 changes: 10 additions & 8 deletions apps/api/routes/engagement/v2/sequence.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* @jest-environment ./integration-test-environment
*/

import { HTTPError } from '@supaglue/schemas';
import type {
CreateContactRequest,
CreateContactResponse,
Expand Down Expand Up @@ -92,17 +93,18 @@ describe('sequence', () => {
test(`Error body`, async () => {
testSequence.steps[0].interval_seconds = 123;

const res = await supaglueClient.engagement.POST('/sequences', {
body: { record: testSequence },
// TODO: Make it so that x-customer-id can be omitted if it was passed into the client at creation time.
params: { header: { 'x-provider-name': 'salesloft', 'x-customer-id': process.env.CUSTOMER_ID! } },
});
const res = (await supaglueClient.engagement
.POST('/sequences', {
body: { record: testSequence },
// TODO: Make it so that x-customer-id can be omitted if it was passed into the client at creation time.
params: { header: { 'x-provider-name': 'salesloft', 'x-customer-id': process.env.CUSTOMER_ID! } },
})
.catch((e) => e as HTTPError<unknown>)) as HTTPError<unknown>;

expect(res).toBeInstanceOf(HTTPError);
expect(res.response.status).toEqual(400);
// Our API spec is wrong and should specify 400 return code with ability to have errors
expect((res.error as typeof res.data)?.errors?.[0].title).toMatch(
'Salesloft only supports intervals in whole days'
);
expect((res.error as any)?.errors?.[0].title).toMatch('Salesloft only supports intervals in whole days');
});

describe.each(['outreach', 'apollo', 'salesloft'])('%s', (providerName) => {
Expand Down
3 changes: 2 additions & 1 deletion apps/api/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"paths": {
"@/*": ["./*"]
},
"plugins": [{ "transform": "typescript-transform-paths" }]
"plugins": [{ "transform": "typescript-transform-paths" }],
"resolveJsonModule": true
},
"ts-node": {
"swc": true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ function SyncConfigDetailsPanelImpl({ syncConfigId }: SyncConfigDetailsPanelImpl
fullSyncEveryNIncrementals: fullSyncEveryNIncrementals ?? undefined,
autoStartOnConnection,
},
commonObjects: commonObjects.map((object) => ({ object } as CommonObjectConfig)),
commonObjects: commonObjects.map((object) => ({ object }) as CommonObjectConfig),
standardObjects: standardObjects.map((object) => ({ object })),
customObjects: customObjects.map((object) => ({ object })),
entities: entityIds.map((entityId) => ({ entityId })),
Expand Down Expand Up @@ -167,7 +167,7 @@ function SyncConfigDetailsPanelImpl({ syncConfigId }: SyncConfigDetailsPanelImpl
strategy,
autoStartOnConnection,
},
commonObjects: commonObjects.map((object) => ({ object } as CommonObjectConfig)),
commonObjects: commonObjects.map((object) => ({ object }) as CommonObjectConfig),
standardObjects: standardObjects.map((object) => ({ object })),
customObjects: customObjects.map((object) => ({ object })),
entities: entityIds.map((entityId) => ({ entityId })),
Expand Down Expand Up @@ -484,9 +484,7 @@ function SyncConfigDetailsPanelImpl({ syncConfigId }: SyncConfigDetailsPanelImpl
<TextField
{...params}
label="Custom objects"
helperText={`Custom objects in ${
selectedProvider?.name
}. (Note: names are case-sensitive. Press enter or comma to add multiple fields. ${
helperText={`Custom objects in ${selectedProvider?.name}. (Note: names are case-sensitive. Press enter or comma to add multiple fields. ${
selectedProvider?.name === 'salesforce' ? 'For Salesforce, these should all end with __c.' : ''
})`}
/>
Expand Down
4 changes: 2 additions & 2 deletions apps/mgmt-ui/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ if (typeof window !== 'undefined') {
api_host: process.env.FRONTEND_URL
? `${process.env.FRONTEND_URL}/ingest`
: window.location.port === '3000'
? `http://${window.location.hostname}:3000/ingest`
: `https://${window.location.hostname}/ingest`,
? `http://${window.location.hostname}:3000/ingest`
: `https://${window.location.hostname}/ingest`,
});
}

Expand Down
3 changes: 2 additions & 1 deletion apps/sync-worker/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"compilerOptions": {
"outDir": "dist",
"rootDir": ".",
"moduleResolution": "node16"
"moduleResolution": "node16",
"resolveJsonModule": true
},
"ts-node": {
"swc": true
Expand Down
3 changes: 2 additions & 1 deletion docs/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// This file is not used in compilation. It is here just for a nice editor experience.
"extends": "@tsconfig/docusaurus/tsconfig.json",
"compilerOptions": {
"baseUrl": "."
"baseUrl": ".",
"resolveJsonModule": true
}
}
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@
"@tsconfig/node18": "^1.0.1",
"@types/eslint": "^8",
"@types/jest": "^29.5.5",
"@types/prettier": "^2",
"@types/prettier": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^5.52.0",
"@typescript-eslint/parser": "^5.52.0",
"eslint": "^8.34.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"husky": "^8.0.3",
"jest": "^29.7.0",
"jest-runner-groups": "^2.2.0",
"lint-staged": "^13.1.2",
"oas-normalize": "^11.0.1",
"prettier": "^2.8.4",
"prettier-plugin-organize-imports": "^3.2.2",
"prettier-plugin-prisma": "^4.12.0",
"prettier": "^3.1.0",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-prisma": "^5.0.0",
"ts-jest": "^29.1.1",
"tsc-files": "^1.1.3",
"tsx": "^3.12.3",
Expand Down
21 changes: 16 additions & 5 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"types": "index.ts",
"packageManager": "[email protected]",
"dependencies": {
"@anatine/zod-openapi": "^2.2.0",
"@aws-sdk/client-sesv2": "^3.437.0",
"@google-cloud/bigquery": "^6.2.0",
"@hubspot/api-client": "9.1.0",
Expand All @@ -16,13 +15,13 @@
"@supaglue/types": "workspace:^",
"@supaglue/utils": "workspace:*",
"@temporalio/proto": "^1.8.6",
"@zodios/core": "^10.9.6",
"async-retry": "^1.3.3",
"axios": "^1.6.0",
"csv-parse": "^5.3.5",
"csv-stringify": "^6.3.0",
"jsforce": "^2.0.0-beta.20",
"odata": "^1.3.2",
"openapi-fetch": "^0.8.1",
"pg": "^8.10.2",
"pg-connection-string": "^2.6.2",
"pg-copy-streams": "^6.0.6",
Expand All @@ -35,7 +34,8 @@
"qs": "^6.11.2",
"svix": "^0.84.1",
"uuid": "^9.0.0",
"zod": "^3.22.4"
"zod": "^3.22.4",
"zod-openapi": "^2.11.0"
},
"devDependencies": {
"@tsconfig/node18": "^1.0.1",
Expand All @@ -46,7 +46,9 @@
"@types/pluralize": "^0.0.29",
"@types/qs": "^6",
"@types/uuid": "^9.0.1",
"openapi3-ts": "^4.1.2",
"concurrently": "^8.2.2",
"openapi-typescript": "^6.7.1",
"prettier": "^3.1.0",
"ts-toolbelt": "9.6.0",
"typescript": "^4.9.5"
},
Expand All @@ -59,7 +61,16 @@
"lint-staged": "run -T lint-staged --no-stash --quiet",
"lint": "run -T eslint",
"test": "SUPAGLUE_LOG_LEVEL=debug jest --selectProjects @supaglue/core --group=unit",
"tsc:watch": "tsc --noEmit --watch"
"tsc:watch": "tsc --noEmit --watch",
"codegen": "yarn download && yarn generate",
"download": "concurrently 'npm:download:*'",
"generate": "concurrently 'npm:generate:*'",
"download:outreach": "curl --compressed https://developers.outreach.io/page-data/api/reference/overview/page-data.json | jq -r .result.data.contentItem.data.redocStoreStr | jq .definition.data | prettier --parser json > ./remotes/impl/outreach/outreach.openapi.json",
"download:salesloft": "curl https://api.apis.guru/v2/specs/salesloft.com/v2/openapi.json | prettier --parser json > ./remotes/impl/salesloft/salesloft.openapi.json",
"download:apollo": "node --loader tsx remotes/impl/apollo/apollo.openapi.ts | prettier --parser json > ./remotes/impl/apollo/apollo.openapi.json",
"generate:outreach": "openapi-typescript ./remotes/impl/outreach/outreach.openapi.json --output ./remotes/impl/outreach/outreach.openapi.gen.d.ts",
"generate:salesloft": "openapi-typescript ./remotes/impl/salesloft/salesloft.openapi.json --output ./remotes/impl/salesloft/salesloft.openapi.gen.d.ts",
"generate:apollo": "openapi-typescript ./remotes/impl/apollo/apollo.openapi.json --output ./remotes/impl/apollo/apollo.openapi.gen.d.ts"
},
"files": [
"dist"
Expand Down
30 changes: 30 additions & 0 deletions packages/core/remotes/impl/apollo/apollo.client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createOpenapiClient } from '@supaglue/schemas';

import type { paths } from './apollo.openapi.gen';
import oas from './apollo.openapi.json';

interface ApolloCredentials {
apiKey: string;
}

export type ApolloClient = ReturnType<typeof createApolloClient>;
export function createApolloClient(creds: ApolloCredentials) {
return createOpenapiClient<paths>({
baseUrl: oas.servers[0].url,
preRequest(input, init) {
if (input && init?.method?.toLowerCase() === 'get') {
const url = new URL(input);
url.searchParams.set('api_key', creds.apiKey);
return [url.toString(), init];
}
try {
return [
input,
{ ...init, body: JSON.stringify({ api_key: creds.apiKey, ...JSON.parse(init?.body as string) }) },
];
} catch {
return [input, init];
}
},
});
}
Loading