|
| 1 | +# App Action Function Template |
| 2 | + |
| 3 | +App Action functions enable communication between apps by providing serverless endpoints that can be invoked through app actions. This template provides a starting point with skeleton code—you must add your custom action logic to meet your specific use case. |
| 4 | + |
| 5 | +## What is an App Action Function? |
| 6 | + |
| 7 | +App Action functions are serverless workloads that run on Contentful's infrastructure to provide enhanced flexibility and customization. Unlike event-based functions that respond to system events, App Actions are explicitly invoked by an app or external system with specific parameters to perform an operation. |
| 8 | + |
| 9 | +Common use cases for App Action functions include: |
| 10 | + |
| 11 | +- Bulk content operations |
| 12 | +- Data synchronization between environments or spaces |
| 13 | +- Integration with external services and APIs |
| 14 | +- Content transformation and migration |
| 15 | +- Custom content validation or enrichment |
| 16 | + |
| 17 | +## Getting Started |
| 18 | + |
| 19 | +### 1. Adding the Function to a Contentful App |
| 20 | + |
| 21 | +#### Creating a New App with the Function |
| 22 | + |
| 23 | +If you want to create a new app that includes the function template, run: |
| 24 | + |
| 25 | +```bash |
| 26 | +npx create-contentful-app@latest --function appaction-call |
| 27 | +``` |
| 28 | + |
| 29 | +This command will generate a basic app template that includes: |
| 30 | + |
| 31 | +- A `functions` folder that contains the template, instructions, and relevant config files. |
| 32 | +- All necessary scripts for building and deploying your function |
| 33 | +- App manifest file |
| 34 | + - This file ensures that Contentful can properly identify, configure, and run your function. |
| 35 | + - For more information see: [Working with Functions](https://www.contentful.com/developers/docs/extensibility/app-framework/working-with-functions/) |
| 36 | + |
| 37 | +#### Adding the Function to an Existing App |
| 38 | + |
| 39 | +If you prefer to add the function to an existing app, you can run the following CLI commands from inside your app directory: |
| 40 | + |
| 41 | +**Interactive Mode** |
| 42 | + |
| 43 | +Run the CLI in interactive mode, which will prompt you for the necessary options: |
| 44 | + |
| 45 | +```bash |
| 46 | +npx --no-install @contentful/app-scripts generate-function |
| 47 | +``` |
| 48 | + |
| 49 | +The interactive process will guide you through: |
| 50 | + |
| 51 | +1. Selecting a function name |
| 52 | +2. Choosing from available function examples |
| 53 | +3. Selecting your preferred language (JavaScript or TypeScript) |
| 54 | + |
| 55 | +**Non-interactive Mode** |
| 56 | + |
| 57 | +For automated workflows or CI/CD pipelines, use the `--ci` flag with required parameters: |
| 58 | + |
| 59 | +```bash |
| 60 | +npx --no-install @contentful/app-scripts generate-function --ci --name <name> --example appaction-call --language typescript |
| 61 | +``` |
| 62 | + |
| 63 | +**Available Parameters:** |
| 64 | + |
| 65 | +- `--name <name>`: Your function name (any value except 'example') |
| 66 | +- `--example <example>`: Template to use (e.g., 'appaction-call', 'external-references') |
| 67 | +- `--language <language>`: 'javascript' or 'typescript' (defaults to typescript if invalid) |
| 68 | +- `--ci`: Enables non-interactive mode |
| 69 | + |
| 70 | +**Example:** |
| 71 | + |
| 72 | +```bash |
| 73 | +npx --no-install @contentful/app-scripts generate-function --ci --name content-processor --example appaction-call --language typescript |
| 74 | +``` |
| 75 | + |
| 76 | +When executed, this command: |
| 77 | + |
| 78 | +- Creates a `functions` directory if one doesn't exist |
| 79 | +- Adds the selected function template with your specified name |
| 80 | +- Creates or updates the `contentful-app-manifest.json` file |
| 81 | +- Updates your `package.json` to include function build commands |
| 82 | + |
| 83 | +> **Note**: All function examples are sourced from the `contentful/apps/function-examples` repository. |
| 84 | +
|
| 85 | +### 2. Connect to an App Definition |
| 86 | + |
| 87 | +If you haven't already created an app definition in Contentful, choose one of the options below. |
| 88 | + |
| 89 | +#### Manually via the Web UI |
| 90 | + |
| 91 | +- [Navigate to the Apps section in your organization](https://app.contentful.com/deeplink?link=app-definition-list) |
| 92 | + |
| 93 | +- Click the "Create App" button |
| 94 | + |
| 95 | +- Fill in the required fields. If you want to test your App Action function using a UI, be sure to select **Page Location** and check the toggle for `Show app in main navigation`. |
| 96 | + |
| 97 | +- Proceed to the [Set Up Your Environment](#3-set-up-your-environment) step. |
| 98 | + |
| 99 | +> **Note**: If you are unfamiliar with how to create a custom app definition in Contentful, please review the documentation here: [Create a Custom App - Tutorial](https://www.contentful.com/developers/docs/extensibility/app-framework/tutorial/?utm_source=webapp&utm_medium=app-listing&utm_campaign=in-app-help) |
| 100 | +
|
| 101 | +#### Via CLI |
| 102 | + |
| 103 | +- Run: `npm run create-app-definition` |
| 104 | +- Answer the prompted questions. Feel free to proceed with the default options provided. |
| 105 | + |
| 106 | + 1. **Name of your application**. |
| 107 | + - This is how your app will be named and it will be displayed in a few places throughout the UI. The default is the name of the folder you created. |
| 108 | + 2. **Select where your app can be rendered**. |
| 109 | + - For testing App Actions, select **Page Location**, as this is where you will be able to test your app actions. Select `y` for showing your app in the main navigation, and then provide a name for the link. |
| 110 | + - If your app is **frontendless** you can skip selecting a location. |
| 111 | + 3. **Contentful CMA endpoint URL**. |
| 112 | + - This refers to the URL used to interact with Contentful's Management APIs. |
| 113 | + 4. **App Parameters**. |
| 114 | + - These are configurable values that can be used to set default values or define custom validation rules. |
| 115 | + 5. The next steps will lead you through the process of providing a Contentful access token to the application and specifying the organization to which the application should be assigned. |
| 116 | + - This will automatically create a `.env` file with these fields for you |
| 117 | + 6. Proceed to [Customize the App Action Function](#4-customize-the-app-action-function) |
| 118 | + |
| 119 | +### 3. Set Up Your Environment |
| 120 | + |
| 121 | +If you created your app definition manually through the web UI, or the CLI did not create one for you, create a `.env` file in the root of your application with your Contentful credentials: |
| 122 | + |
| 123 | +```env |
| 124 | +CONTENTFUL_ORG_ID=your-organization-id |
| 125 | +CONTENTFUL_APP_DEF_ID=your-app-definition-id |
| 126 | +CONTENTFUL_ACCESS_TOKEN=your-access-token |
| 127 | +``` |
| 128 | + |
| 129 | +These variables authenticate your function with Contentful and link it to your app definition. |
| 130 | + |
| 131 | +> **Note**: You can generate an access token from your Space Settings menu. For the other values, you can find them in your Contentful organization and app settings. |
| 132 | +
|
| 133 | +### 4. Customize the App Action Function |
| 134 | + |
| 135 | +Open `functions/appaction-call-template.ts` and add your custom logic based on your specific requirements. |
| 136 | + |
| 137 | +#### App Action Function Example |
| 138 | + |
| 139 | +Here's an example that creates a new entry of a specific content type: |
| 140 | + |
| 141 | +```ts |
| 142 | +// Define your App Action parameters |
| 143 | +type CreateEntryParams = { |
| 144 | + contentTypeId: string; |
| 145 | + fields: Record<string, any>; |
| 146 | +}; |
| 147 | + |
| 148 | +export const handler: FunctionEventHandler<FunctionTypeEnum.AppActionCall> = async ( |
| 149 | + event: AppActionRequest<'Custom', CreateEntryParams>, |
| 150 | + context: FunctionEventContext |
| 151 | +) => { |
| 152 | + // Access the CMA client |
| 153 | + const cma = context.cma!; |
| 154 | + |
| 155 | + try { |
| 156 | + // Extract parameters from the request |
| 157 | + const { contentTypeId, fields } = event.body; |
| 158 | + |
| 159 | + // Get the space and environment from the context |
| 160 | + const spaceId = context.spaceId; |
| 161 | + const environmentId = context.environmentId; |
| 162 | + |
| 163 | + if (!contentTypeId || !fields) { |
| 164 | + return { |
| 165 | + error: 'Missing required parameters: contentTypeId and fields are required', |
| 166 | + }; |
| 167 | + } |
| 168 | + |
| 169 | + // Create an entry using the CMA client |
| 170 | + const entry = await cma.entry.create({ |
| 171 | + spaceId, |
| 172 | + environmentId, |
| 173 | + contentTypeId, |
| 174 | + fields: Object.entries(fields).reduce((acc, [key, value]) => { |
| 175 | + acc[key] = { 'en-US': value }; |
| 176 | + return acc; |
| 177 | + }, {}), |
| 178 | + }); |
| 179 | + |
| 180 | + return { |
| 181 | + success: true, |
| 182 | + entry: { |
| 183 | + id: entry.sys.id, |
| 184 | + contentType: entry.sys.contentType.sys.id, |
| 185 | + createdAt: entry.sys.createdAt, |
| 186 | + }, |
| 187 | + }; |
| 188 | + } catch (error) { |
| 189 | + console.error('Error executing App Action:', error); |
| 190 | + return { |
| 191 | + success: false, |
| 192 | + error: error.message || 'An error occurred while processing your request', |
| 193 | + }; |
| 194 | + } |
| 195 | +}; |
| 196 | +``` |
| 197 | + |
| 198 | +### 5. Build and Upload Your Function |
| 199 | + |
| 200 | +Currently, the only way to deploy a function is through the CLI. To do so, run the following commands: |
| 201 | + |
| 202 | +```bash |
| 203 | +# Build your function |
| 204 | +npm run build |
| 205 | + |
| 206 | +# Upload your function to Contentful |
| 207 | +npm run upload |
| 208 | +``` |
| 209 | + |
| 210 | +The build step is essential since the upload process relies on the compiled code. The CLI may prompt for additional details (e.g., the CMA endpoint URL) and offer to activate the bundle post-upload. |
| 211 | + |
| 212 | +> **Note**: For more information on the differences between `upload` and `upload-ci`, see the [Create Contentful App Documentation](https://www.contentful.com/developers/docs/extensibility/app-framework/create-contentful-app/) |
| 213 | +
|
| 214 | +### 6. Create an App Action |
| 215 | + |
| 216 | +To make your function accessible, you need to create an App Action that links to it. There are two ways to do this: |
| 217 | + |
| 218 | +#### Via the Contentful Web App |
| 219 | + |
| 220 | +1. Open your app definition in the Contentful web app |
| 221 | +2. Navigate to the "App Actions" tab |
| 222 | +3. Click "Create App Action" and fill in the required information: |
| 223 | + - Name: A descriptive name for your action |
| 224 | + - App Action ID: A unique identifier for this action |
| 225 | + - Type: Select "Function Invocation" |
| 226 | + - Function: Select your uploaded function |
| 227 | +4. Click "Create" |
| 228 | + |
| 229 | +#### Via the Command Line |
| 230 | + |
| 231 | +You can programmatically create an App Action using the following command: |
| 232 | + |
| 233 | +```bash |
| 234 | +npm run upsert-actions |
| 235 | +``` |
| 236 | + |
| 237 | +You will need to have set the environment variables described in the [Set Up Your Environment](#3-set-up-your-environment) step. |
| 238 | + |
| 239 | +Alternatively, you can pass them as arguments: |
| 240 | + |
| 241 | +```bash |
| 242 | +npm run upsert-actions -- --organizationId=<your_org_id> --definitionId=<your_app_id> --token=<your_token> |
| 243 | +``` |
| 244 | + |
| 245 | +The `upsert-actions` command will create the App Action if it doesn't exist, or update it if it does, linking it to your function. |
| 246 | + |
| 247 | +If you're adding actions programmatically, you must update the `actions` array in your `contentful-app-manifest.json` file: |
| 248 | + |
| 249 | +```json |
| 250 | +"actions": [ |
| 251 | + { |
| 252 | + "id": "yourCustomActionId", // Unique identifier for your action, No Hyphens Allowed |
| 253 | + "name": "Your Custom Action Name", // Display name shown in the UI |
| 254 | + "type": "function-invocation", // Keep this as is for function-based actions |
| 255 | + "functionId": "appactionCall", // Must match the function ID in the functions array |
| 256 | + "category": "Custom", // Action category |
| 257 | + "parameters": [] // Parameters needed by the action |
| 258 | + } |
| 259 | +] |
| 260 | +``` |
| 261 | + |
| 262 | +## Additional Resources |
| 263 | + |
| 264 | +- [Contentful App Functions Documentation](https://www.contentful.com/developers/docs/extensibility/app-framework/functions/) |
| 265 | +- [Working with Functions](https://www.contentful.com/developers/docs/extensibility/app-framework/working-with-functions/) |
| 266 | +- [App Actions Overview](https://www.contentful.com/developers/docs/extensibility/app-framework/app-actions/) |
0 commit comments