Skip to content

Commit 3418e98

Browse files
MarlonJDjosefaidt
andauthored
feature(function): add custom functions documentation for AWS Amplify-backend (#8176)
* feature(function): add custom functions documentation for AWS Amplify Gen 2 @aws-amplify/amplify-backend/1602 * chore(function): rename function handler and update handler file path, remove go lambda alpha package * docs(functions): improve documentation for Python and Go functions, correcting capitalization and enhancing clarity * docs(functions): clarify function invocation instructions and improve code examples in custom functions documentation * chore: fix capitalization in documentation. * Update src/pages/[platform]/build-a-backend/functions/custom-functions/index.mdx Co-authored-by: josef <[email protected]> * Update src/pages/[platform]/build-a-backend/functions/custom-functions/index.mdx --------- Co-authored-by: josef <[email protected]>
1 parent b4cbc15 commit 3418e98

File tree

3 files changed

+247
-3
lines changed

3 files changed

+247
-3
lines changed

cspell.json

+14-3
Original file line numberDiff line numberDiff line change
@@ -1618,14 +1618,25 @@
16181618
"knowledgebases",
16191619
"rehype",
16201620
"assetlinks",
1621-
"AMPLIFYRULES"
1621+
"AMPLIFYRULES",
1622+
"manylinux",
1623+
"GOARCH",
1624+
"norpc"
1625+
],
1626+
"flagWords": [
1627+
"hte",
1628+
"full-stack",
1629+
"Full-stack",
1630+
"Full-Stack",
1631+
"sudo"
16221632
],
1623-
"flagWords": ["hte", "full-stack", "Full-stack", "Full-Stack", "sudo"],
16241633
"patterns": [
16251634
{
16261635
"name": "youtube-embed-ids",
16271636
"pattern": "/embedId=\".*\" /"
16281637
}
16291638
],
1630-
"ignoreRegExpList": ["youtube-embed-ids"]
1639+
"ignoreRegExpList": [
1640+
"youtube-embed-ids"
1641+
]
16311642
}

src/directory/directory.mjs

+3
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ export const directory = {
448448
},
449449
{
450450
path: 'src/pages/[platform]/build-a-backend/functions/modify-resources-with-cdk/index.mdx'
451+
},
452+
{
453+
path: 'src/pages/[platform]/build-a-backend/functions/custom-functions/index.mdx'
451454
}
452455
]
453456
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
2+
3+
export const meta = {
4+
title: 'Custom functions',
5+
description:
6+
'Use another AWS Lambda runtimes like Python, Golang to perform tasks and customize workflows.',
7+
platforms: [
8+
'android',
9+
'angular',
10+
'flutter',
11+
'javascript',
12+
'nextjs',
13+
'react',
14+
'react-native',
15+
'swift',
16+
'vue'
17+
]
18+
};
19+
20+
export function getStaticPaths() {
21+
return getCustomStaticPath(meta.platforms);
22+
}
23+
24+
export function getStaticProps(context) {
25+
return {
26+
props: {
27+
platform: context.params.platform,
28+
meta
29+
}
30+
};
31+
}
32+
33+
AWS Amplify Gen 2 functions are AWS Lambda functions that can be used to perform tasks and customize workflows in your Amplify app. Functions can be written in Node.js, Python, Go, or any [other language supported by AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html).
34+
35+
<Callout warning>
36+
37+
**Note:** [Fullstack Git-based environments](https://docs.amplify.aws/react/how-amplify-works/concepts/#fullstack-git-based-environments) do not support Docker for functions bundling out of the box.
38+
39+
</Callout>
40+
41+
In this guide, you will learn how to create Python and Go functions with Amplify functions. The examples shown in this guide do not use Docker to build functions. Instead, the examples use commands that run on your host system to build, and as such require the necessary tooling for the language you are using for your functions.
42+
43+
## Python
44+
45+
To get started, create a new directory and a resource file, `amplify/functions/say-hello/resource.ts`. Then, define the function with `defineFunction`:
46+
```ts title="amplify/functions/say-hello/resource.ts"
47+
import { execSync } from "node:child_process";
48+
import * as path from "node:path";
49+
import { fileURLToPath } from "node:url";
50+
import { defineFunction } from "@aws-amplify/backend";
51+
import { DockerImage, Duration } from "aws-cdk-lib";
52+
import { Code, Function, Runtime } from "aws-cdk-lib/aws-lambda";
53+
54+
const functionDir = path.dirname(fileURLToPath(import.meta.url));
55+
56+
export const sayHelloFunctionHandler = defineFunction(
57+
(scope) =>
58+
new Function(scope, "say-hello", {
59+
handler: "index.handler",
60+
runtime: Runtime.PYTHON_3_9, // or any other python version
61+
timeout: Duration.seconds(20), // default is 3 seconds
62+
code: Code.fromAsset(functionDir, {
63+
bundling: {
64+
image: DockerImage.fromRegistry("dummy"),
65+
local: {
66+
tryBundle(outputDir: string) {
67+
execSync(
68+
`python3 -m pip install -r ${path.join(functionDir, "requirements.txt")} -t ${path.join(outputDir)} --platform manylinux2014_x86_64 --only-binary=:all:`
69+
);
70+
execSync(`rsync -rLv ${functionDir}/* ${path.join(outputDir)}`);
71+
return true;
72+
},
73+
},
74+
},
75+
}),
76+
})
77+
);
78+
```
79+
80+
Next, create the corresponding handler file at `amplify/functions/say-hello/index.py`. This is where your function code will go.
81+
82+
```ts title="amplify/functions/say-hello/index.py"
83+
import json
84+
85+
def handler(event, context):
86+
return {
87+
"statusCode": 200,
88+
"body": json.dumps({
89+
"message": "Hello World",
90+
}),
91+
}
92+
```
93+
94+
The handler file _must_ export a function named "handler". This is the entry point to your function. For more information on writing functions, refer to the [AWS documentation for Lambda function handlers using Python](https://docs.aws.amazon.com/lambda/latest/dg/python-handler.html).
95+
96+
If you need Python packages, you can add them to a `requirements.txt` file in the same directory as your handler file. The `bundling` option in the `Code.fromAsset` method will install these packages for you.
97+
Create a `requirements.txt` file in the same directory as your handler file. This file should contain the names of the packages you want to install. For example:
98+
99+
```txt title="amplify/functions/say-hello/requirements.txt"
100+
request==2.25.1
101+
some-other-package>=1.0.0
102+
```
103+
104+
You're now ready to deploy your python function. Next is the same process as the Node.js/TypeScript function. Go to [Common steps for all languages](#common-steps-for-all-languages) to continue.
105+
106+
## Go
107+
To get started, Create a new directory and a resource file, `amplify/functions/say-hello/resource.ts`. Then, define the function with `defineFunction`:
108+
109+
```ts title="amplify/functions/say-hello/resource.ts"
110+
import { execSync } from "node:child_process";
111+
import * as path from "node:path";
112+
import { fileURLToPath } from "node:url";
113+
import { defineFunction } from "@aws-amplify/backend";
114+
import { DockerImage, Duration } from "aws-cdk-lib";
115+
import { Code, Function, Runtime } from "aws-cdk-lib/aws-lambda";
116+
import { defineFunction } from "@aws-amplify/backend";
117+
import { DockerImage, Duration } from "aws-cdk-lib";
118+
import { Code, Function, Runtime } from "aws-cdk-lib/aws-lambda";
119+
export const sayHelloFunctionHandler = defineFunction(
120+
(scope) =>
121+
new Function(scope, "say-hello", {
122+
handler: "bootstrap",
123+
runtime: Runtime.PROVIDED_AL2023,
124+
timeout: Duration.seconds(3), // default is 3 seconds
125+
code: Code.fromAsset(functionDir, {
126+
bundling: {
127+
image: DockerImage.fromRegistry("dummy"),
128+
local: {
129+
tryBundle(outputDir: string) {
130+
execSync(`rsync -rLv ${functionDir}/* ${path.join(outputDir)}`);
131+
execSync(
132+
`cd ${path.join(outputDir)} && GOARCH=amd64 GOOS=linux go build -tags lambda.norpc -o ${path.join(outputDir)}/bootstrap ${functionDir}/main.go`
133+
);
134+
return true;
135+
},
136+
},
137+
},
138+
}),
139+
}),
140+
);
141+
```
142+
143+
Next, create the corresponding handler file at `amplify/functions/say-hello/main.go`. This is where your function code will go.
144+
145+
```go title="amplify/functions/say-hello/main.go"
146+
package main
147+
148+
import (
149+
"context"
150+
"fmt"
151+
152+
"github.com/aws/aws-lambda-go/lambda"
153+
)
154+
155+
type Event struct {
156+
Arguments Arguments `json:"arguments"`
157+
}
158+
159+
type Arguments struct {
160+
Title string `json:"phone"`
161+
Msg string `json:"msg"`
162+
}
163+
164+
func HandleRequest(ctx context.Context, event Event) (string, error) {
165+
fmt.Println("Received event: ", event)
166+
167+
// fmt.Println("Message sent to: ", event.Arguments.Msg)
168+
// You can use lambda arguments in your code
169+
170+
return "Hello World!", nil
171+
}
172+
173+
func main() {
174+
lambda.Start(HandleRequest)
175+
}
176+
```
177+
178+
Then you should run the following command to build the go function:
179+
```bash title="terminal" showLineNumbers={false}
180+
go mod init lambda
181+
```
182+
then run to install the dependencies.
183+
184+
```bash title="terminal" showLineNumbers={false}
185+
go mod tidy
186+
```
187+
188+
You're now ready to deploy your golang function. Next is the same process as the Node.js/TypeScript function.
189+
190+
## Common steps for all languages
191+
192+
Regardless of the language used, your function needs to be added to your backend.
193+
```ts title="amplify/backend.ts"
194+
// highlight-next-line
195+
import { sayHelloFunctionHandler } from './functions/say-hello/resource';
196+
197+
defineBackend({
198+
// highlight-next-line
199+
sayHelloFunctionHandler,
200+
});
201+
```
202+
203+
Now when you run `npx ampx sandbox` or deploy your app on Amplify, it will include your function.
204+
205+
To invoke your function, we recommend adding your [function as a handler for a custom query with your Amplify Data resource](/[platform]/build-a-backend/data/custom-business-logic/). To get started, open your `amplify/data/resource.ts` file and specify a new query in your schema:
206+
207+
```ts title="amplify/data/resource.ts"
208+
import { sayHelloFunctionHandler } from "../functions/say-hello/resource"
209+
210+
const schema = a.schema({
211+
// highlight-start
212+
sayHello: a
213+
.query()
214+
.arguments({
215+
name: a.string(),
216+
})
217+
.returns(a.string())
218+
.handler(a.handler.function(sayHelloFunctionHandler)),
219+
// highlight-end
220+
})
221+
222+
export type Schema = ClientSchema<typeof schema>
223+
224+
export const data = defineData({
225+
schema,
226+
authorizationModes: {
227+
defaultAuthorizationMode: "iam",
228+
},
229+
})
230+
```

0 commit comments

Comments
 (0)