From dec005b91fa34f072363639f063374e3e03a0da8 Mon Sep 17 00:00:00 2001 From: Bryant Park Date: Fri, 19 Jul 2024 11:57:20 -0400 Subject: [PATCH] Add final method call to request context header (#478) * Add final method call to all request-sending methods except asyncIter * Mark asyncIter-originated fetchPage calls * Fix asyncIter to actually fetch next pages * Add changeset * Fix runAssignEmployeeToVentureTest * Stop exposing calledByAsyncIter argument in fetchPage * Fix semantic merge conflict with queries PR * Add final method call to applyQuery * Make return type of augment fn a Partial * Add rationale for augment fn in comment --- .changeset/strange-mails-drop.md | 6 ++ packages/client/src/MinimalClientContext.ts | 5 ++ packages/client/src/actions/applyAction.ts | 11 +++- packages/client/src/createMinimalClient.ts | 1 + packages/client/src/object/aggregate.ts | 4 +- packages/client/src/object/fetchPage.ts | 20 +++++-- .../client/src/objectSet/createObjectSet.ts | 31 +++++++--- packages/client/src/queries/applyQuery.ts | 8 ++- ...> addUserAgentAndRequestContextHeaders.ts} | 40 ++++++------- .../client/src/util/augmentRequestContext.ts | 57 +++++++++++++++++++ .../src/runAssignEmployeeToVentureTest.ts | 4 +- 11 files changed, 147 insertions(+), 40 deletions(-) create mode 100644 .changeset/strange-mails-drop.md rename packages/client/src/util/{addUserAgent.ts => addUserAgentAndRequestContextHeaders.ts} (66%) create mode 100644 packages/client/src/util/augmentRequestContext.ts diff --git a/.changeset/strange-mails-drop.md b/.changeset/strange-mails-drop.md new file mode 100644 index 000000000..b1413cf35 --- /dev/null +++ b/.changeset/strange-mails-drop.md @@ -0,0 +1,6 @@ +--- +"@osdk/client.api": patch +"@osdk/client": patch +--- + +Add final method call to request context header diff --git a/packages/client/src/MinimalClientContext.ts b/packages/client/src/MinimalClientContext.ts index 24585275e..787f4b16f 100644 --- a/packages/client/src/MinimalClientContext.ts +++ b/packages/client/src/MinimalClientContext.ts @@ -23,12 +23,17 @@ declare const tag: unique symbol; export type ClientCacheKey = {} & { readonly [tag]: void }; +export type RequestContext = { + finalMethodCall?: string; +}; + export interface MinimalClient extends SharedClientContext { ontologyRid: string | Promise; ontologyProvider: OntologyProvider; logger?: Logger; objectSetFactory: ObjectSetFactory; clientCacheKey: ClientCacheKey; + requestContext: RequestContext; } export type MinimalClientParams = { diff --git a/packages/client/src/actions/applyAction.ts b/packages/client/src/actions/applyAction.ts index 050a55cfc..da18186fb 100644 --- a/packages/client/src/actions/applyAction.ts +++ b/packages/client/src/actions/applyAction.ts @@ -24,7 +24,8 @@ import type { import type { DataValue } from "@osdk/internal.foundry"; import { Ontologies, OntologiesV2 } from "@osdk/internal.foundry"; import type { MinimalClient } from "../MinimalClientContext.js"; -import { addUserAgent } from "../util/addUserAgent.js"; +import { addUserAgentAndRequestContextHeaders } from "../util/addUserAgentAndRequestContextHeaders.js"; +import { augmentRequestContext } from "../util/augmentRequestContext.js"; import { toDataValue } from "../util/toDataValue.js"; import { ActionValidationError } from "./ActionValidationError.js"; @@ -45,9 +46,13 @@ export async function applyAction< ): Promise< ActionReturnTypeForOptions > { + const clientWithHeaders = addUserAgentAndRequestContextHeaders( + augmentRequestContext(client, _ => ({ finalMethodCall: "applyAction" })), + action, + ); if (Array.isArray(parameters)) { const response = await OntologiesV2.Actions.applyActionBatchV2( - addUserAgent(client, action), + clientWithHeaders, await client.ontologyRid, action.apiName, { @@ -65,7 +70,7 @@ export async function applyAction< : undefined) as ActionReturnTypeForOptions; } else { const response = await OntologiesV2.Actions.applyActionV2( - addUserAgent(client, action), + clientWithHeaders, await client.ontologyRid, action.apiName, { diff --git a/packages/client/src/createMinimalClient.ts b/packages/client/src/createMinimalClient.ts index 71e3789cb..7c9c807a8 100644 --- a/packages/client/src/createMinimalClient.ts +++ b/packages/client/src/createMinimalClient.ts @@ -63,6 +63,7 @@ export function createMinimalClient( ontologyRid: metadata.ontologyRid, logger: options.logger, clientCacheKey: {} as ClientCacheKey, + requestContext: {}, } satisfies Omit< MinimalClient, "ontologyProvider" diff --git a/packages/client/src/object/aggregate.ts b/packages/client/src/object/aggregate.ts index 1bcba8137..d8ab0de88 100644 --- a/packages/client/src/object/aggregate.ts +++ b/packages/client/src/object/aggregate.ts @@ -33,7 +33,7 @@ import { modernToLegacyAggregationClause } from "../internal/conversions/modernT import { modernToLegacyGroupByClause } from "../internal/conversions/modernToLegacyGroupByClause.js"; import { modernToLegacyWhereClause } from "../internal/conversions/modernToLegacyWhereClause.js"; import type { MinimalClient } from "../MinimalClientContext.js"; -import { addUserAgent } from "../util/addUserAgent.js"; +import { addUserAgentAndRequestContextHeaders } from "../util/addUserAgentAndRequestContextHeaders.js"; import type { ArrayElement } from "../util/ArrayElement.js"; /** @deprecated use `aggregate` */ @@ -79,7 +79,7 @@ export async function aggregate< body.where = modernToLegacyWhereClause(req.$where); } const result = await OntologiesV2.OntologyObjectSets.aggregateObjectSetV2( - addUserAgent(clientCtx, objectType), + addUserAgentAndRequestContextHeaders(clientCtx, objectType), await clientCtx.ontologyRid, { objectSet, diff --git a/packages/client/src/object/fetchPage.ts b/packages/client/src/object/fetchPage.ts index 53790c822..a38c15bf1 100644 --- a/packages/client/src/object/fetchPage.ts +++ b/packages/client/src/object/fetchPage.ts @@ -40,7 +40,7 @@ import type { } from "@osdk/internal.foundry"; import { OntologiesV2 } from "@osdk/internal.foundry"; import type { MinimalClient } from "../MinimalClientContext.js"; -import { addUserAgent } from "../util/addUserAgent.js"; +import { addUserAgentAndRequestContextHeaders } from "../util/addUserAgentAndRequestContextHeaders.js"; import { convertWireToOsdkObjects } from "./convertWireToOsdkObjects.js"; export function augment< @@ -95,7 +95,7 @@ async function fetchInterfacePage< objectSet: ObjectSet, ): Promise> { const result = await OntologiesV2.OntologyObjectsV2.searchObjectsForInterface( - addUserAgent(client, interfaceType), + addUserAgentAndRequestContextHeaders(client, interfaceType), await client.ontologyRid, interfaceType.apiName, applyFetchArgs(args, { @@ -131,9 +131,19 @@ export async function fetchPageInternal< args: FetchPageArgs = {}, ): Promise> { if (objectType.type === "interface") { - return await fetchInterfacePage(client, objectType, args, objectSet) as any; // fixme + return await fetchInterfacePage( + client, + objectType, + args, + objectSet, + ) as any; // fixme } else { - return await fetchObjectPage(client, objectType, args, objectSet) as any; // fixme + return await fetchObjectPage( + client, + objectType, + args, + objectSet, + ) as any; // fixme } } @@ -237,7 +247,7 @@ export async function fetchObjectPage< objectSet: ObjectSet, ): Promise> { const r = await OntologiesV2.OntologyObjectSets.loadObjectSetV2( - addUserAgent(client, objectType), + addUserAgentAndRequestContextHeaders(client, objectType), await client.ontologyRid, applyFetchArgs(args, { objectSet, diff --git a/packages/client/src/objectSet/createObjectSet.ts b/packages/client/src/objectSet/createObjectSet.ts index d04243ba3..10d0d3903 100644 --- a/packages/client/src/objectSet/createObjectSet.ts +++ b/packages/client/src/objectSet/createObjectSet.ts @@ -35,12 +35,12 @@ import type { ObjectSet as WireObjectSet } from "@osdk/internal.foundry"; import { modernToLegacyWhereClause } from "../internal/conversions/modernToLegacyWhereClause.js"; import type { MinimalClient } from "../MinimalClientContext.js"; import { aggregate } from "../object/aggregate.js"; -import { convertWireToOsdkObjects } from "../object/convertWireToOsdkObjects.js"; import { fetchPageInternal, fetchPageWithErrorsInternal, } from "../object/fetchPage.js"; import { fetchSingle, fetchSingleWithErrors } from "../object/fetchSingle.js"; +import { augmentRequestContext } from "../util/augmentRequestContext.js"; import { isWireObjectSet } from "../util/WireObjectSet.js"; function isObjectTypeDefinition( @@ -77,21 +77,24 @@ export function createObjectSet( const base: Omit, keyof BaseObjectSet> = { aggregate: (aggregate).bind( globalThis, - clientCtx, + augmentRequestContext(clientCtx, _ => ({ finalMethodCall: "aggregate" })), objectType, objectSet, ), fetchPage: fetchPageInternal.bind( globalThis, - clientCtx, + augmentRequestContext(clientCtx, _ => ({ finalMethodCall: "fetchPage" })), objectType, objectSet, ) as ObjectSet["fetchPage"], fetchPageWithErrors: fetchPageWithErrorsInternal.bind( globalThis, - clientCtx, + augmentRequestContext( + clientCtx, + _ => ({ finalMethodCall: "fetchPageWithErrors" }), + ), objectType, objectSet, ) as ObjectSet["fetchPageWithErrors"], @@ -148,7 +151,15 @@ export function createObjectSet( ObjectOrInterfacePropertyKeysFrom2, boolean, "throw" - > = await base.fetchPage({ $nextPageToken }); + > = await fetchPageInternal( + augmentRequestContext( + clientCtx, + _ => ({ finalMethodCall: "asyncIter" }), + ), + objectType, + objectSet, + { $nextPageToken }, + ); $nextPageToken = result.nextPageToken; for (const obj of result.data) { @@ -175,7 +186,10 @@ export function createObjectSet( }; return await fetchSingle( - clientCtx, + augmentRequestContext( + clientCtx, + _ => ({ finalMethodCall: "fetchOne" }), + ), objectType, options, withPk, @@ -201,7 +215,10 @@ export function createObjectSet( }; return await fetchSingleWithErrors( - clientCtx, + augmentRequestContext( + clientCtx, + _ => ({ finalMethodCall: "fetchOneWithErrors" }), + ), objectType, options, withPk, diff --git a/packages/client/src/queries/applyQuery.ts b/packages/client/src/queries/applyQuery.ts index b322a3f3e..3a899d843 100644 --- a/packages/client/src/queries/applyQuery.ts +++ b/packages/client/src/queries/applyQuery.ts @@ -38,7 +38,8 @@ import { OntologiesV2 } from "@osdk/internal.foundry"; import { createAttachmentFromRid } from "../createAttachmentFromRid.js"; import type { MinimalClient } from "../MinimalClientContext.js"; import { createObjectSet } from "../objectSet/createObjectSet.js"; -import { addUserAgent } from "../util/addUserAgent.js"; +import { addUserAgentAndRequestContextHeaders } from "../util/addUserAgentAndRequestContextHeaders.js"; +import { augmentRequestContext } from "../util/augmentRequestContext.js"; import { toDataValue } from "../util/toDataValue.js"; import { toDataValueQueries } from "../util/toDataValueQueries.js"; @@ -53,7 +54,10 @@ export async function applyQuery< QueryReturnType > { const response = await OntologiesV2.QueryTypes.executeQueryV2( - addUserAgent(client, query), + addUserAgentAndRequestContextHeaders( + augmentRequestContext(client, _ => ({ finalMethodCall: "applyQuery" })), + query, + ), await client.ontologyRid, query.apiName, { diff --git a/packages/client/src/util/addUserAgent.ts b/packages/client/src/util/addUserAgentAndRequestContextHeaders.ts similarity index 66% rename from packages/client/src/util/addUserAgent.ts rename to packages/client/src/util/addUserAgentAndRequestContextHeaders.ts index 6add1bd50..eec649969 100644 --- a/packages/client/src/util/addUserAgent.ts +++ b/packages/client/src/util/addUserAgentAndRequestContextHeaders.ts @@ -18,24 +18,26 @@ import type { ObjectOrInterfaceDefinition } from "@osdk/api"; import { createFetchHeaderMutator } from "@osdk/shared.net.fetch"; import type { MinimalClient } from "../MinimalClientContext.js"; -export function addUserAgent( +export const addUserAgentAndRequestContextHeaders = ( client: MinimalClient, withMetadata: Pick, -): MinimalClient { - if (withMetadata.osdkMetadata) { - return { - ...client, - fetch: createFetchHeaderMutator( - client.fetch, - (headers) => { - headers.set( - "Fetch-User-Agent", - withMetadata.osdkMetadata!.extraUserAgent, - ); - return headers; - }, - ), - }; - } - return client; -} +): MinimalClient => ({ + ...client, + fetch: createFetchHeaderMutator( + client.fetch, + (headers) => { + headers.set( + "X-OSDK-Request-Context", + JSON.stringify(client.requestContext), + ); + + if (withMetadata.osdkMetadata) { + headers.set( + "Fetch-User-Agent", + withMetadata.osdkMetadata.extraUserAgent, + ); + } + return headers; + }, + ), +}); diff --git a/packages/client/src/util/augmentRequestContext.ts b/packages/client/src/util/augmentRequestContext.ts new file mode 100644 index 000000000..68081e2ce --- /dev/null +++ b/packages/client/src/util/augmentRequestContext.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Palantir Technologies, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { MinimalClient, RequestContext } from "../MinimalClientContext.js"; + +/** +Returns a client with its `requestContext` merged with the result of applying +`augment` to its `requestContext`. + +The second argument is an `Partial`-returning `augment` function +instead of a `RequestContext` object to make referencing the current request +context easier. For example, modifying the `fetchPage` function to add its name +to the object set's called method chain could look like: +``` +augmentRequestContext( + clientContext, + ctx => ({ methodChain: [...ctx.methodChain, "fetchPage"] }) +) +``` +or +``` +augmentRequestContext( + clientContext, + ({ methodChain }) => ({ methodChain: [...methodChain, "fetchPage"] }) +) +``` +instead of +``` +augmentRequestContext( + clientContext, + { methodChain: [...clientContext.requestContext.methodChain, "fetchPage"] } +) +``` +*/ +export const augmentRequestContext = ( + client: MinimalClient, + augment: (ctx: RequestContext) => Partial, +): MinimalClient => ({ + ...client, + requestContext: { + ...client.requestContext, + ...augment(client.requestContext), + }, +}); diff --git a/packages/e2e.sandbox.catchall/src/runAssignEmployeeToVentureTest.ts b/packages/e2e.sandbox.catchall/src/runAssignEmployeeToVentureTest.ts index 69e3e6164..e75806270 100644 --- a/packages/e2e.sandbox.catchall/src/runAssignEmployeeToVentureTest.ts +++ b/packages/e2e.sandbox.catchall/src/runAssignEmployeeToVentureTest.ts @@ -42,8 +42,8 @@ export async function runAssignEmployeeToVentureTest() { const { data: [venture] } = await client(Venture).fetchPage(); const r = await client(assignEmployee1).applyAction({ - "employee-1": emp, - "venture-1": venture, + "employee-1": emp.id, + "venture-1": venture.ventureId, }, { $validateOnly: true, });