Skip to content

Commit c88d775

Browse files
committed
[srvls][SRVOCF-278] Add Quarkus functions docs
1 parent f4e2980 commit c88d775

9 files changed

+370
-7
lines changed

_topic_map.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2973,6 +2973,8 @@ Topics:
29732973
# File: serverless-developing-go-functions
29742974
# - Name: Developing Python functions
29752975
# File: serverless-developing-python-functions
2976+
# - Name: Developing Quarkus functions
2977+
# File: serverless-developing-quarkus-functions
29762978
# - Name: Functions development reference guide
29772979
# File: serverless-functions-reference-guide
29782980
# Networking
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Module included in the following assemblies
2+
//
3+
// * /serverless/functions/serverless-developing-quarkus-functions.adoc
4+
5+
[id="serverless-functions-quarkus-return-value-types_{context}"]
6+
= Permitted types
7+
8+
The input and output types of a function can be any of the following:
9+
10+
* `void`
11+
* `String`
12+
* `byte[]`
13+
* Primitive types and their wrappers (for example, `int` and `Integer`).
14+
* A JavaBean, if its attributes are of types listed here.
15+
* A map, list, or array of the types in this list.
16+
* The special `CloudEvents<T>` type, where the `<T>` type parameter is of a type in this list.
17+
18+
.Example
19+
[source,java]
20+
----
21+
public class Functions {
22+
public List<Integer> getIds();
23+
public Purchase[] getPurchasesByName(String name);
24+
public String getNameById(int id);
25+
public Map<String,Integer> getNameIdMapping();
26+
public void processImage(byte[] img);
27+
}
28+
----
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Module included in the following assemblies
2+
//
3+
// * /serverless/functions/serverless-developing-quarkus-functions.adoc
4+
5+
[id="serverless-invoking-quarkus-functions_{context}"]
6+
= About invoking Quarkus functions
7+
8+
You can create a Quarkus project that responds to CloudEvents, or one that responds to simple HTTP requests. CloudEvents in Knative are transported over HTTP as a POST request, so either function type can listen and respond to incoming HTTP requests.
9+
10+
When an incoming request is received, Quarkus functions are invoked with an instance of a permitted type.
11+
12+
.Function invocation options
13+
[options="header",cols="d,d,m"]
14+
|====
15+
|Invocation method |Data type contained in the instance |Example of data
16+
|HTTP POST request | JSON object in the body of the request |`{ "customerId": "0123456", "productId": "6543210" }`
17+
|HTTP GET request | Data in the query string |`?customerId=0123456&productId=6543210`
18+
|`CloudEvent` | JSON object in the `data` property |`{ "customerId": "0123456", "productId": "6543210" }`
19+
|====
20+
21+
The following example shows a function that receives and processes the `customerId` and `productId` purchase data that is listed in the previous table:
22+
23+
.Example Quarkus function
24+
[source,java]
25+
----
26+
public class Functions {
27+
@Funq
28+
public void processPurchase(Purchase purchase) {
29+
// process the purchase
30+
}
31+
}
32+
----
33+
34+
The corresponding `Purchase` JavaBean class that contains the purchase data looks as follows:
35+
36+
.Example class
37+
[source,java]
38+
----
39+
public class Purchase {
40+
private long customerId;
41+
private long productId;
42+
// getters and setters
43+
}
44+
----
45+
46+
[id="serverless-invoking-quarkus-functions-examples_{context}"]
47+
== Invocation examples
48+
49+
The following example code defines three functions named `withBeans`, `withCloudEvent`, and `withBinary`;
50+
51+
.Example
52+
[source,java]
53+
----
54+
import io.quarkus.funqy.Funq;
55+
import io.quarkus.funqy.knative.events.CloudEvent;
56+
57+
public class Input {
58+
private String message;
59+
60+
// getters and setters
61+
}
62+
63+
public class Output {
64+
private String message;
65+
66+
// getters and setters
67+
}
68+
69+
public class Functions {
70+
@Funq
71+
public Output withBeans(Input in) {
72+
// function body
73+
}
74+
75+
@Funq
76+
public CloudEvent<Output> withCloudEvent(CloudEvent<Input> in) {
77+
// function body
78+
}
79+
80+
@Funq
81+
public void withBinary(byte[] in) {
82+
// function body
83+
}
84+
}
85+
----
86+
87+
The `withBeans` function of the `Functions` class can be invoked by:
88+
89+
* An HTTP POST request with a JSON body:
90+
+
91+
[source,terminal]
92+
----
93+
$ curl "http://localhost:8080/withBeans" -X POST \
94+
-H "Content-Type: application/json" \
95+
-d '{"message": "Hello there."}'
96+
----
97+
* An HTTP GET request with query parameters:
98+
+
99+
[source,terminal]
100+
----
101+
$ curl "http://localhost:8080/withBeans?message=Hello%20there." -X GET
102+
----
103+
* A `CloudEvent` object in binary encoding:
104+
+
105+
[source,terminal]
106+
----
107+
$ curl "http://localhost:8080/" -X POST \
108+
-H "Content-Type: application/json" \
109+
-H "Ce-SpecVersion: 1.0" \
110+
-H "Ce-Type: withBeans" \
111+
-H "Ce-Source: cURL" \
112+
-H "Ce-Id: 42" \
113+
-d '{"message": "Hello there."}'
114+
----
115+
* A `CloudEvent` object in structured encoding:
116+
+
117+
[source,terminal]
118+
----
119+
$ curl http://localhost:8080/ \
120+
-H "Content-Type: application/cloudevents+json" \
121+
-d '{ "data": {"message":"Hello there."},
122+
"datacontenttype": "application/json",
123+
"id": "42",
124+
"source": "curl",
125+
"type": "withBeans",
126+
"specversion": "1.0"}'
127+
----
128+
129+
The `withCloudEvent` function of the `Functions` class can be invoked by using a `CloudEvent` object, similarly to the `withBeans` function. However, unlike `withBeans`, `withCloudEvent` cannot be invoked with a plain HTTP request.
130+
131+
The `withBinary` function of the `Functions` class can be invoked by:
132+
133+
* A `CloudEvent` object in binary encoding:
134+
+
135+
[source]
136+
----
137+
$ curl "http://localhost:8080/" -X POST \
138+
-H "Content-Type: application/octet-stream" \
139+
-H "Ce-SpecVersion: 1.0"\
140+
-H "Ce-Type: withBinary" \
141+
-H "Ce-Source: cURL" \
142+
-H "Ce-Id: 42" \
143+
--data-binary '@img.jpg'
144+
----
145+
* A `CloudEvent` object in structured encoding:
146+
+
147+
[source]
148+
----
149+
$ curl http://localhost:8080/ \
150+
-H "Content-Type: application/cloudevents+json" \
151+
-d "{ \"data_base64\": \"$(base64 --wrap=0 img.jpg)\",
152+
\"datacontenttype\": \"application/octet-stream\",
153+
\"id\": \"42\",
154+
\"source\": \"curl\",
155+
\"type\": \"withBinary\",
156+
\"specversion\": \"1.0\"}"
157+
----
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Module included in the following assemblies
2+
//
3+
// * /serverless/functions/serverless-developing-quarkus-functions.adoc
4+
5+
[id="serverless-quarkus-cloudevent-attributes_{context}"]
6+
= CloudEvent attributes
7+
8+
If you need to read or write the attributes of a CloudEvent, such as `type` or `subject`, you can use the `CloudEvent<T>` generic interface and the `CloudEventBuilder` builder. The `<T>` type parameter must be one of the permitted types.
9+
10+
In the following example, `CloudEventBuilder` is used to return success or failure of processing the purchase:
11+
12+
[source,java]
13+
----
14+
public class Functions {
15+
16+
private boolean _processPurchase(Purchase purchase) {
17+
// do stuff
18+
}
19+
20+
public CloudEvent<Void> processPurchase(CloudEvent<Purchase> purchaseEvent) {
21+
System.out.println("subject is: " + purchaseEvent.subject());
22+
23+
if (!_processPurchase(purchaseEvent.data())) {
24+
return CloudEventBuilder.create()
25+
.type("purchase.error")
26+
.build();
27+
}
28+
return CloudEventBuilder.create()
29+
.type("purchase.success")
30+
.build();
31+
}
32+
}
33+
----
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Module included in the following assemblies
2+
//
3+
// * /serverless/functions/serverless-developing-quarkus-functions.adoc
4+
5+
[id="serverless-quarkus-function-return-values_{context}"]
6+
= Quarkus function return values
7+
8+
Functions can return an instance of:
9+
10+
* Any type from the list of permitted types.
11+
* The `Uni<T>` type, where the `<T>` type parameter can be of any type from the permitted types.
12+
13+
The `Uni<T>` type is useful if a function calls asynchronous APIs, because the returned object is serialized in the same format as the received object. For example:
14+
15+
* If a function receives an HTTP request, then the returned object is sent in the body of an HTTP response.
16+
* If a function receives a `CloudEvent` object in binary encoding, then the returned object is sent in the data property of a binary-encoded `CloudEvent` object.
17+
18+
The following example shows a function that fetches a list of purchases:
19+
20+
.Example command
21+
[source,java]
22+
----
23+
public class Functions {
24+
@Funq
25+
public List<Purchase> getPurchasesByName(String name) {
26+
// logic to retrieve purchases
27+
}
28+
}
29+
----
30+
31+
* Invoking this function through an HTTP request produces an HTTP response that contains a list of purchases in the body of the response.
32+
* Invoking this function through an incoming `CloudEvent` object produces a `CloudEvent` response with a list of purchases in the `data` property.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Module included in the following assemblies
2+
//
3+
// * /serverless/functions/serverless-developing-quarkus-functions.adoc
4+
5+
[id="serverless-quarkus-template_{context}"]
6+
= Quarkus function template structure
7+
8+
When you create a Quarkus function by using the `kn` CLI, the project directory looks similar to a typical Maven project.
9+
10+
Both `http` and `event` trigger functions have the same template structure:
11+
12+
.Template structure
13+
[source,terminal]
14+
----
15+
.
16+
├── func.yaml <1>
17+
├── mvnw
18+
├── mvnw.cmd
19+
├── pom.xml <2>
20+
├── README.md
21+
└── src
22+
├── main
23+
│ ├── java
24+
│ │ └── functions
25+
│ │ ├── Function.java <3>
26+
│ │ ├── Input.java
27+
│ │ └── Output.java
28+
│ └── resources
29+
│ └── application.properties
30+
└── test
31+
└── java
32+
└── functions <4>
33+
├── FunctionTest.java
34+
└── NativeFunctionIT.java
35+
----
36+
<1> Used to determine the image name and registry.
37+
<2> The Project Object Model (POM) file contains project configuration, such as information about dependencies. You can add additional dependencies by modifying this file.
38+
+
39+
.Example of additional dependencies
40+
[source,xml]
41+
----
42+
...
43+
<dependencies>
44+
<dependency>
45+
<groupId>junit</groupId>
46+
<artifactId>junit</artifactId>
47+
<version>4.11</version>
48+
<scope>test</scope>
49+
</dependency>
50+
<dependency>
51+
<groupId>org.assertj</groupId>
52+
<artifactId>assertj-core</artifactId>
53+
<version>3.8.0</version>
54+
<scope>test</scope>
55+
</dependency>
56+
</dependencies>
57+
...
58+
----
59+
+
60+
Dependencies are downloaded during the first compilation.
61+
<3> The function project must contain a Java method annotated with `@Funq`. You can place this method in the `Function.java` class.
62+
<4> Contains simple test cases that can be used to test your function locally.

modules/serverless-testing-python-functions.adoc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
[id="serverless-testing-python-functions_{context}"]
66
= Testing Python functions
77

8-
Python functions can be tested locally on your computer. The default project contains a `test_func.py` file, which provides a simple unit test for functions.
8+
You can test Python functions locally on your computer. The default project contains a `test_func.py` file, which provides a simple unit test for functions.
9+
10+
[NOTE]
11+
====
12+
The default test framework for Python functions is `unittest`. You can use a different test framework if you prefer.
13+
====
914

1015
.Prerequisites
1116

@@ -18,14 +23,9 @@ $ pip install -r requirements.txt
1823

1924
.Procedure
2025

21-
. After you have installed the dependencies, run the tests:
26+
* After you have installed the dependencies, run the tests:
2227
+
2328
[source,terminal]
2429
----
2530
$ python3 test_func.py
2631
----
27-
28-
[NOTE]
29-
====
30-
The default test framework for Python functions is `unittest`. You can use a different test framework if you prefer.
31-
====
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Module included in the following assemblies
2+
//
3+
// * /serverless/functions/serverless-developing-quarkus-functions.adoc
4+
5+
[id="serverless-testing-quarkus-functions_{context}"]
6+
= Testing Quarkus functions
7+
8+
You can test Quarkus functions locally on your computer by running the Maven tests that are included in the project template.
9+
10+
.Procedure
11+
12+
* Run the Maven tests:
13+
+
14+
[source,terminal]
15+
----
16+
$ ./mvnw test
17+
----

0 commit comments

Comments
 (0)