fix: Use composite API by default for all queries#1877
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the SOQL query flow to use Salesforce’s Composite API by default, reducing failures caused by long queries and consolidating the “fetch columns + fetch results” work into a single Salesforce request.
Changes:
- Add a
useCompositeApitoggle to the/api/queryclient + controllers and default it on. - Introduce
ApiQuery.queryComposite()to run the query + columns subrequests via Salesforce Composite API. - Wire all query controllers (api/desktop/canvas/web-extension) to route requests to
queryComposite()when enabled.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/shared/data/src/lib/client-data.ts | Adds useCompositeApi parameter to query calls; needs parity for cached query path. |
| libs/salesforce-api/src/lib/api-query.ts | Adds queryComposite() implementation using Composite API. |
| apps/api/src/app/controllers/sf-query.controller.ts | Adds useCompositeApi query param and switches between composite vs non-composite query. |
| apps/jetstream-desktop/src/controllers/sf-query.desktop.controller.ts | Same routing change for desktop query controller. |
| apps/jetstream-canvas/src/controllers/sf-query.canvas.controller.ts | Same routing change for canvas query controller. |
| apps/jetstream-web-extension/src/controllers/sf-query.web-ext.controller.ts | Same routing change for web-extension query controller. |
88660dd to
73533bc
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (4)
apps/api/src/app/controllers/sf-query.controller.ts:32
useCompositeApiis parsed withBooleanQueryParamSchema, which transforms a missing query param tofalse(because it is.nullish().transform(...)). That means callers who don’t passuseCompositeApiwill not use the composite API, which conflicts with the PR intent of using composite by default.
query: z.object({
isTooling: BooleanQueryParamSchema,
includeDeletedRecords: BooleanQueryParamSchema,
useCompositeApi: BooleanQueryParamSchema,
}),
apps/jetstream-desktop/src/controllers/sf-query.desktop.controller.ts:27
useCompositeApiis parsed withBooleanQueryParamSchema, which transforms a missing query param tofalse. If the query param isn’t provided, this endpoint will default to the non-composite query path, which contradicts the PR’s goal of using composite by default.
query: z.object({
isTooling: BooleanQueryParamSchema,
includeDeletedRecords: BooleanQueryParamSchema,
useCompositeApi: BooleanQueryParamSchema,
}),
apps/jetstream-canvas/src/controllers/sf-query.canvas.controller.ts:27
useCompositeApiusesBooleanQueryParamSchema, which turns an omitted param intofalse. That makes the non-composite path the default when the param is missing, which doesn’t match the PR’s intent of defaulting to composite.
query: z.object({
isTooling: BooleanQueryParamSchema,
includeDeletedRecords: BooleanQueryParamSchema,
useCompositeApi: BooleanQueryParamSchema,
}),
apps/jetstream-web-extension/src/controllers/sf-query.web-ext.controller.ts:27
useCompositeApicurrently usesBooleanQueryParamSchema, which treats a missing query param asfalse. That makes the default behavior non-composite when the param is omitted, which is inconsistent with the PR intent of using composite by default.
query: z.object({
isTooling: BooleanQueryParamSchema,
includeDeletedRecords: BooleanQueryParamSchema,
useCompositeApi: BooleanQueryParamSchema,
}),
This avoids Salesforce errors for request headers being too large and allows a single request for column metadata and query results
73533bc to
800cce6
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
apps/api/src/app/controllers/sf-query.controller.ts:76
- useCompositeApi currently defaults to false when the query param is omitted (BooleanQueryParamSchema is nullish and transforms missing to false). That means /api/query will still use the non-composite path by default for older callers, which undermines the PR goal of using the composite API by default to avoid long-query URL failures. Consider treating composite as the default unless explicitly disabled via ?useCompositeApi=false.
const isTooling = query.isTooling;
const includeDeletedRecords = query.includeDeletedRecords;
const useCompositeApi = query.useCompositeApi;
const soql = body.query;
const results = useCompositeApi
? await jetstreamConn.query.queryComposite(soql, isTooling, includeDeletedRecords)
: await jetstreamConn.query.query(soql, isTooling, includeDeletedRecords);
apps/jetstream-web-extension/src/controllers/sf-query.web-ext.controller.ts:70
- useCompositeApi will be false when the query param is omitted (BooleanQueryParamSchema transforms null/undefined to false), so this route still uses the non-composite query path by default for older callers. If the intention is to use the composite API by default, consider defaulting to composite unless explicitly disabled via ?useCompositeApi=false.
const isTooling = query.isTooling;
const includeDeletedRecords = query.includeDeletedRecords;
const useCompositeApi = query.useCompositeApi;
const soql = body.query;
const results = useCompositeApi
? await jetstreamConn!.query.queryComposite(soql, isTooling, includeDeletedRecords)
: await jetstreamConn!.query.query(soql, isTooling, includeDeletedRecords);
apps/jetstream-desktop/src/controllers/sf-query.desktop.controller.ts:69
- useCompositeApi becomes false when the query param is omitted (BooleanQueryParamSchema transforms missing to false), so this controller will still default to the non-composite path for older callers. If composite should be the default behavior, consider treating it as enabled unless explicitly set to false via ?useCompositeApi=false.
const isTooling = query.isTooling;
const includeDeletedRecords = query.includeDeletedRecords;
const useCompositeApi = query.useCompositeApi;
const soql = body.query;
const results = useCompositeApi
? await jetstreamConn!.query.queryComposite(soql, isTooling, includeDeletedRecords)
: await jetstreamConn!.query.query(soql, isTooling, includeDeletedRecords);
apps/jetstream-canvas/src/controllers/sf-query.canvas.controller.ts:69
- useCompositeApi currently defaults to false when the query param is absent (BooleanQueryParamSchema transforms null/undefined to false), so this route still uses the non-composite query path by default for older callers. If the intent is composite-by-default, consider treating composite as enabled unless explicitly disabled via ?useCompositeApi=false.
const isTooling = query.isTooling;
const includeDeletedRecords = query.includeDeletedRecords;
const useCompositeApi = query.useCompositeApi;
const soql = body.query;
const results = useCompositeApi
? await jetstreamConn!.query.queryComposite(soql, isTooling, includeDeletedRecords)
: await jetstreamConn!.query.query(soql, isTooling, includeDeletedRecords);
This avoids Salesforce errors for request headers being too large and allows a single request for column metadata and query results