Funqy HTTP Binding (Standalone)
The guide walks through quickstart code to show you how you can deploy Funqy as a standalone service and invoke on Funqy functions using HTTP.
The Funqy HTTP binding is not a replacement for REST over HTTP. Because Funqy needs to be portable across a lot of different protocols and function providers its HTTP binding is very minimalistic and you will lose REST features like linking and the ability to leverage HTTP features like cache-control and conditional GETs. You may want to consider using Quarkus’s Jakarta REST, Spring MVC, or Vert.x Web Reactive Routes support instead, although Funqy will have less overhead than these alternatives (except Vert.x which is still super fast). |
先决条件
完成这个指南,你需要:
-
大概15分钟
-
编辑器
-
JDK 17+ installed with
JAVA_HOME
configured appropriately -
Apache Maven 3.9.9
-
如果你愿意的话,还可以选择使用Quarkus CLI
-
Read about Funqy Basics. This is a short read!
The Quickstart
克隆 Git 仓库: git clone https://github.com/quarkusio/quarkus-quickstarts.git
,或下载一个 存档 。
The solution is located in the funqy-http-quickstart
directory.
The Code
If you look at the Java code, you’ll see that there is no HTTP specific API. Its just simple Java methods
annotated with @Funq
. Simple, easy, straightforward.
Maven Dependencies
To write Funqy HTTP functions, simply include the quarkus-funqy-http
dependency into your Quarkus pom.xml
file:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-http</artifactId>
</dependency>
Execute Funqy HTTP functions
The URL path to execute a function is the function name. For example if your function name is foo
then the URL path
to execute the function would be /foo
.
The HTTP POST or GET methods can be used to invoke on a function. The return value of the function is marshalled to JSON using the Jackson JSON library. Jackson annotations can be used. If your function has an input parameter, a POST invocation must use JSON as the input type. Jackson is also used here for unmarshalling.
You can invoke the hello
function defined in PrimitiveFunctions.java
by pointing your browser to http://localhost:8080/hello
Invoking the other functions in the quickstart requires an HTTP POST.
To execute the greet
function defined in GreetingFunction.java
invoke this curl script.
curl "http://localhost:8080/greet" \
-X POST \
-H "Content-Type: application/json" \
-d '{"name":"Bill"}'
Primitive types can also be passed as input using the standard JSON mapping for them.
To execute the toLowerCase
function defined in PrimitiveFunctions.java
invoke this curl script:
curl "http://localhost:8080/toLowerCase" \
-X POST \
-H "Content-Type: application/json" \
-d '"HELLO WORLD"'
To execute the double
function defined in PrimitiveFunctions.java
invoke this curl script:
curl "http://localhost:8080/double" \
-X POST \
-H "Content-Type: application/json" \
-d '2'
GET Query Parameter Mapping
For GET requests, the Funqy HTTP Binding also has a query parameter mapping for function input parameters.
Only bean style classes and java.util.Map
can be used for your input parameter. For bean style
classes, query parameter names are mapped to properties on the bean class. Here’s an example of a simple
Map
:
@Funq
public String hello(Map<String, Integer> map) {
...
}
Key values must be a primitive type (except char) or String
. Values can be primitives (except char), String
, OffsetDateTime
or a complex
bean style class. For the above example, here’s the corresponding curl request:
curl "http://localhost:8080/a=1&b=2"
The map
input parameter of the hello
function would have the key value pairs: a
→1, b
→2.
Bean style classes can also be use as the input parameter type. Here’s an example:
public class Person {
String first;
String last;
public String getFirst() { return first; }
public void setFirst(String first) { this.first = first; }
public String getLast() { return last; }
public void setLast(String last) { this.last = last; }
}
public class MyFunctions {
@Funq
public String greet(Person p) {
return "Hello " + p.getFirst() + " " + p.getLast();
}
}
Property values can be any primitive type except char
. It can also be String
, and OffsetDateTime
.
OffsetDateTime
query param values must be in ISO-8601 format.
You can invoke on this using an HTTP GET and query parameters:
curl "http://localhost:8080/greet?first=Bill&last=Burke"
In the above request, the query parameter names are mapped to corresponding properties in the input class.
The input class can also have nested bean classes. Expanding on the previous example:
public class Family {
private Person dad;
private Person mom;
public Person getDad() { return dad; }
public void setDad(Person dad) { this.dad = dad; }
public Person getMom() { return mom; }
public void setMom(Person mom) { this.mom = mom; }
}
public class MyFunctions {
@Funq
public String greet(Family family) {
...
}
}
In this case, query parameters for nested values use the .
notation. For example:
curl "http://localhost:8080/greet?dad.first=John&dad.last=Smith&mom.first=Martha&mom.last=Smith"
java.util.List
and Set
are also supported as property values. For example:
public class Family {
...
List<String> pets;
}
public class MyFunctions {
@Funq
public String greet(Family family) {
...
}
}
To invoke a GET request, just list the pets
query parameter multiple times.
curl "http://localhost:8080/greet?pets=itchy&pets=scratchy"
For more complex types, List
and Set
members must have an identifier in the
query parameter. For example:
public class Family {
...
List<Person> kids;
}
public class MyFunctions {
@Funq
public String greet(Family family) {
...
}
}
Each kids
query parameter must identify the kid they are referencing so that
the runtime can figure out which
property values go to which members in the list. Here’s the curl request:
curl "http://localhost:8080/greet?kids.1.first=Buffy&kids.2.first=Charlie"
The above URL uses the value 1
and 2
to identity the target member of the list, but any unique
string can be used.
A property can also be a java.util.Map
. The key of the map can be any primitive type and String
.
For example:
public class Family {
...
Map<String, String> address;
}
public class MyFunctions {
@Funq
public String greet(Family family) {
...
}
}
The corresponding call would look like this:
curl "http://localhost:8080/greet?address.state=MA&address.city=Boston"
If your Map
value is a complex type, then just continue the notation by adding the property to set at the end.
public class Family {
...
Map<String, Address> addresses;
}
public class MyFunctions {
@Funq
public String greet(Family family) {
...
}
}
curl "http://localhost:8080/greet?addresses.home.state=MA&addresses.home.city=Boston"