Skip to content

Commit ac05a0d

Browse files
feat: update function examples to highlight how to init a cma client within an app function [EXT-6303] (#9630)
* feat: update autotagger example to highlight how to init a cma client within an app function [EXT-6303] * feat: update comment-bot example to highlight how to init a cma client within an app function [EXT-6303] * feat: update function-appaction example to highlight how to init a cma client within an app function [EXT-6303] * feat: update appaction-call template to highlight how to init a cma client within an app function [EXT-6303]
1 parent e997c73 commit ac05a0d

File tree

8 files changed

+120
-36
lines changed

8 files changed

+120
-36
lines changed

Diff for: examples/autotagger/functions/autotagger.ts

+38-21
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,38 @@ import {
33
AppActionRequest,
44
AppEventEntry,
55
AppEventRequest,
6+
EntryAutosaveEventPayload,
67
FunctionEventContext,
8+
FunctionTypeEnum,
79
} from '@contentful/node-apps-toolkit/lib/requests/typings';
8-
import type { EntryProps, PlainClientAPI, Link } from 'contentful-management';
10+
import {
11+
type EntryProps,
12+
type PlainClientAPI,
13+
type Link,
14+
createClient,
15+
} from 'contentful-management';
916
import { buildAutotagPrompts } from './prompts';
1017

1118
const DEFAULT_API_URL = 'https://api.openai.com/v1/chat/completions';
1219
const DEFAULT_MODEL = 'gpt-4o';
1320

21+
function initContentfulManagementClient(context: FunctionEventContext): PlainClientAPI {
22+
if (!context.cmaClientOptions) {
23+
throw new Error(
24+
'Contentful Management API client options are only provided for certain function types. To learn more about using the CMA within functions, see https://www.contentful.com/developers/docs/extensibility/app-framework/functions/#using-the-cma.'
25+
);
26+
}
27+
return createClient(context.cmaClientOptions, {
28+
type: 'plain',
29+
defaults: {
30+
spaceId: context.spaceId,
31+
environmentId: context.environmentId,
32+
},
33+
});
34+
}
35+
1436
async function fetchOpenAiResponse(
15-
entry: EntryProps,
37+
entry: EntryAutosaveEventPayload | EntryProps,
1638
apiKey: string,
1739
apiUrl: string,
1840
model: string
@@ -74,12 +96,12 @@ async function createNewTags(cma: PlainClientAPI, newTags: string[]): Promise<vo
7496

7597
async function updateEntryTags(
7698
cma: PlainClientAPI,
77-
entry: EntryProps,
99+
entry: EntryAutosaveEventPayload | EntryProps,
78100
tags: Link<'Tag'>[]
79101
): Promise<void> {
80102
try {
81103
await cma.entry.patch(
82-
{ entryId: entry.sys.id },
104+
{ entryId: entry.sys.id, version: entry.sys.version },
83105
[
84106
{
85107
op: 'replace',
@@ -98,7 +120,7 @@ async function updateEntryTags(
98120
}
99121

100122
async function autotag(
101-
entry: EntryProps,
123+
entry: EntryAutosaveEventPayload | EntryProps,
102124
cma: PlainClientAPI,
103125
appInstallationParameters: Record<string, any>
104126
) {
@@ -123,45 +145,40 @@ async function autotag(
123145
}
124146
}
125147

126-
const appActionHandler: EventHandler<'appaction.call'> = async (
127-
event: AppActionRequest<'Custom' | 'Entries.v1.0' | 'Notification.v1.0'>,
148+
const appActionHandler: EventHandler<FunctionTypeEnum.AppActionCall> = async (
149+
event: AppActionRequest<'Custom', { entryId: string }>,
128150
context: FunctionEventContext
129151
) => {
130152
const {
131153
body: { entryId },
132-
} = event as AppActionRequest<'Custom', { entryId: string }>;
133-
const { cma, appInstallationParameters } = context as FunctionEventContext & {
134-
cma: PlainClientAPI;
135-
};
154+
} = event;
136155
try {
156+
const cma = initContentfulManagementClient(context);
137157
const entry = await cma.entry.get({ entryId });
138-
await autotag(entry, cma, appInstallationParameters);
158+
await autotag(entry, cma, context.appInstallationParameters);
139159
return { success: true };
140160
} catch (error) {
141161
console.error('Error handling action:', error);
142162
return { success: false };
143163
}
144164
};
145165

146-
const appEventHandler: EventHandler<'appevent.handler'> = async (
166+
const appEventHandler: EventHandler<FunctionTypeEnum.AppEventHandler> = async (
147167
event: AppEventRequest,
148168
context: FunctionEventContext
149169
) => {
150-
const { cma, appInstallationParameters } = context as FunctionEventContext & {
151-
cma: PlainClientAPI;
152-
};
153170
try {
171+
const cma = initContentfulManagementClient(context);
154172
const { body: entry } = event as AppEventEntry;
155-
await autotag(entry, cma, appInstallationParameters);
173+
await autotag(entry as EntryAutosaveEventPayload, cma, context.appInstallationParameters);
156174
} catch (error) {
157175
console.error('Error handling event:', error);
158176
}
159177
};
160178

161-
export const handler: EventHandler<'appaction.call' | 'appevent.handler'> = async (
162-
event: AppActionRequest | AppEventRequest,
163-
context: FunctionEventContext
164-
) => {
179+
export const handler: EventHandler<
180+
FunctionTypeEnum.AppActionCall | FunctionTypeEnum.AppEventHandler
181+
> = async (event, context) => {
165182
if (event.type === 'appaction.call') {
166183
return appActionHandler(event, context);
167184
} else if (event.type === 'appevent.handler') {

Diff for: examples/autotagger/functions/prompts.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { EntryAutosaveEventPayload } from '@contentful/node-apps-toolkit';
12
import type { EntryProps } from 'contentful-management';
23

3-
export function buildAutotagPrompts(entry: EntryProps) {
4+
export function buildAutotagPrompts(entry: EntryAutosaveEventPayload | EntryProps) {
45
return [
56
{
67
role: 'system',

Diff for: examples/autotagger/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@contentful/f36-tokens": "4.2.0",
99
"@contentful/react-apps-toolkit": "1.2.16",
1010
"@emotion/css": "^11.13.5",
11-
"contentful-management": "11.48.0",
11+
"contentful-management": "11.50.0",
1212
"react": "19.0.0",
1313
"react-dom": "19.0.0"
1414
},

Diff for: examples/function-appaction/functions/example.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,36 @@ import { FunctionEventHandler } from '@contentful/node-apps-toolkit';
22
import {
33
AppActionRequest,
44
FunctionEventContext,
5+
FunctionTypeEnum,
56
} from '@contentful/node-apps-toolkit/lib/requests/typings';
7+
import { type PlainClientAPI, createClient } from 'contentful-management';
68

79
// When using a 'Custom' category App Action, you may define the parameters that the App Action will receive.
810
// This should match what you configured in the App Action definition.
911
type MyCustomAppActionParameters = {
1012
foo: string;
1113
};
1214

13-
export const handler: FunctionEventHandler<'appaction.call'> = async (
15+
function initContentfulManagementClient(context: FunctionEventContext): PlainClientAPI {
16+
if (!context.cmaClientOptions) {
17+
throw new Error(
18+
'Contentful Management API client options are only provided for certain function types. To learn more about using the CMA within functions, see https://www.contentful.com/developers/docs/extensibility/app-framework/functions/#using-the-cma.'
19+
);
20+
}
21+
return createClient(context.cmaClientOptions, {
22+
type: 'plain',
23+
defaults: {
24+
spaceId: context.spaceId,
25+
environmentId: context.environmentId,
26+
},
27+
});
28+
}
29+
30+
export const handler: FunctionEventHandler<FunctionTypeEnum.AppActionCall> = async (
1431
event: AppActionRequest<'Custom', MyCustomAppActionParameters>, // For better typing, specify your App Action category and, if using the 'Custom' category, parameter types here
1532
context: FunctionEventContext
1633
) => {
17-
const cma = context.cma!; // App Action Call Functions have access to the authenticated CMA client
34+
const cma = initContentfulManagementClient(context); // App Action Call Functions have access to the authenticated CMA client
1835

1936
const { foo } = event.body; // Access the parameters passed to the App Action Call via the event body
2037

Diff for: examples/function-comment-bot/functions/bot-actions/bot-action-base.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
1-
import { PlainClientAPI } from 'contentful-management';
1+
import { type FunctionEventContext } from '@contentful/node-apps-toolkit';
2+
import { type PlainClientAPI, createClient } from 'contentful-management';
23

34
export class BotActionBase {
5+
initContentfulManagementClient(context: FunctionEventContext): PlainClientAPI {
6+
if (!context.cmaClientOptions) {
7+
throw new Error(
8+
'Contentful Management API client options are only provided for certain function types. To learn more about using the CMA within functions, see https://www.contentful.com/developers/docs/extensibility/app-framework/functions/#using-the-cma.'
9+
);
10+
}
11+
return createClient(context.cmaClientOptions, {
12+
type: 'plain',
13+
defaults: {
14+
spaceId: context.spaceId,
15+
environmentId: context.environmentId,
16+
},
17+
});
18+
}
19+
420
async loadContentType(cma: PlainClientAPI, entryId: string) {
521
return cma.entry.get({ entryId });
622
}

Diff for: examples/function-comment-bot/functions/bot-actions/publish-button-action.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ const publicationWidget = {
1111
export class PublishButtonAction extends BotActionBase implements BotAction {
1212
async execute(params: BotActionParams): Promise<void> {
1313
const { commentBody, context, parentEntityId } = params;
14-
if (!isManagementContextInvocation(context)) {
15-
throw new Error('This action requires the Contentful Management API client to be available');
16-
}
17-
const { cma } = context;
14+
15+
const cma = this.initContentfulManagementClient(context);
1816

1917
const contentType = await this.loadContentType(cma, parentEntityId);
2018
const contentTypeId = contentType.sys.contentType.sys.id;

Diff for: function-examples/appaction-call/javascript/appaction-call-template.js

+22-3
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,35 @@
33
*
44
* This template provides a starting point for creating an App Action function.
55
* You'll need to implement your custom logic in the handler function below.
6-
*
6+
*/
7+
8+
import { createClient } from 'contentful-management';
9+
10+
function initContentfulManagementClient(context) {
11+
if (!context.cmaClientOptions) {
12+
throw new Error(
13+
'Contentful Management API client options are only provided for certain function types. To learn more about using the CMA within functions, see https://www.contentful.com/developers/docs/extensibility/app-framework/functions/#using-the-cma.'
14+
);
15+
}
16+
return createClient(context.cmaClientOptions, {
17+
type: 'plain',
18+
defaults: {
19+
spaceId: context.spaceId,
20+
environmentId: context.environmentId,
21+
},
22+
});
23+
}
24+
25+
/**
726
* This handler is invoked when your App Action is called
827
*
928
* @param {Object} event - Contains the parameters passed to your App Action
1029
* @param {Object} context - Provides access to the CMA client and other context information
1130
* @returns {Object} The response from your App Action
1231
*/
1332
export const handler = async (event, context) => {
14-
// Access the authenticated CMA client to interact with Contentful
15-
const cma = context.cma;
33+
// Instantiate an authenticated CMA client to interact with Contentful
34+
const cma = initContentfulManagementClient(context);
1635

1736
// Extract parameters from the event body
1837
// const { paramName } = event.body;

Diff for: function-examples/appaction-call/typescript/appaction-call-template.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import {
1+
import type {
22
FunctionEventContext,
33
FunctionEventHandler,
44
FunctionTypeEnum,
55
AppActionRequest,
66
} from '@contentful/node-apps-toolkit';
7+
import { type PlainClientAPI, createClient } from 'contentful-management';
78

89
/**
910
* App Action Function Template
@@ -21,6 +22,21 @@ type AppActionParameters = {
2122
// booleanParam: boolean;
2223
};
2324

25+
function initContentfulManagementClient(context: FunctionEventContext): PlainClientAPI {
26+
if (!context.cmaClientOptions) {
27+
throw new Error(
28+
'Contentful Management API client options are only provided for certain function types. To learn more about using the CMA within functions, see https://www.contentful.com/developers/docs/extensibility/app-framework/functions/#using-the-cma.'
29+
);
30+
}
31+
return createClient(context.cmaClientOptions, {
32+
type: 'plain',
33+
defaults: {
34+
spaceId: context.spaceId,
35+
environmentId: context.environmentId,
36+
},
37+
});
38+
}
39+
2440
/**
2541
* This handler is invoked when your App Action is called
2642
*
@@ -31,8 +47,8 @@ export const handler: FunctionEventHandler<FunctionTypeEnum.AppActionCall> = asy
3147
event: AppActionRequest<'Custom', AppActionParameters>,
3248
context: FunctionEventContext
3349
) => {
34-
// Access the authenticated CMA client to interact with Contentful
35-
const cma = context.cma!;
50+
// Instantiate an authenticated CMA client to interact with Contentful
51+
const cma = initContentfulManagementClient(context);
3652

3753
// Extract parameters from the event body
3854
// const { paramName } = event.body;

0 commit comments

Comments
 (0)