Funqy HTTP Binding (Standalone)

指南将逐步介绍快速入门代码,向您展示如何部署 Funqy 作为独立服务,以及使用 HTTP 调用 Funqy 函数。

Funqy HTTP 绑定不会替代通过 HTTP 的 REST。由于 Funqy 需要在许多不同的协议和函数提供程序之间实现可移植性,因此其 HTTP 绑定非常极简,您将失去 REST 功能,例如链接以及利用缓存控制和条件 GET 等 HTTP 功能的能力。您可能希望考虑使用 Quarkus 的 Jakarta REST、Spring MVC 或 Vert.x Web Reactive Routes 支持,尽管 Funqy 将比这些替代方案(除了仍然非常快的 Vert.x)具有更少的开销。

Prerequisites

include::./_includes/prerequisites.adoc[]* 阅读有关 Funqy Basics 的信息。这是一篇短文!

The Quickstart

克隆 Git 存储库: git clone $${quickstarts-base-url}.git,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。

解决方法位于 funqy-http-quickstart directory 中。

The Code

如果您查看 Java 代码,会发现没有 HTTP 特定的 API。它只是用 @Funq 注释过的简单 Java 方法。简单、容易、直接。

Maven Dependencies

要编写 Funqy HTTP 函数,只需将 quarkus-funqy-http 依赖项包含到您的 Quarkus pom.xml 文件中:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-funqy-http</artifactId>
</dependency>

Build Project

mvn clean quarkus:dev

这将在 Quarkus dev 模式下启动您的函数。

Execute Funqy HTTP functions

执行函数的 URL 路径是函数名称。例如,如果您的函数名称为 foo,则执行函数的 URL 路径将为 /foo

可以使用 HTTP POST 或 GET 方法调用函数。函数的返回值使用 Jackson JSON 库编组到 JSON 中。可以使用 Jackson 注释。如果您的函数有输入参数,POST 调用必须使用 JSON 作为输入类型。Jackson 也用于此处进行取消编组。

您可以通过将浏览器指向 [role="bare"][role="bare"]http://localhost:8080/hello 来调用在 PrimitiveFunctions.java 中定义的 hello 函数。

调用快速入门中的其他函数需要 HTTP POST。要执行在 GreetingFunction.java 中定义的 greet 函数,请调用此 curl 脚本。

curl "http://localhost:8080/greet" \
-X POST \
-H "Content-Type: application/json" \
-d '{"name":"Bill"}'

也可以使用标准的 JSON 映射将基本类型传递为输入。若要执行在 PrimitiveFunctions.java 中定义的 toLowerCase 函数,请调用此 curl 脚本:

curl "http://localhost:8080/toLowerCase" \
-X POST \
-H "Content-Type: application/json" \
-d '"HELLO WORLD"'

若要执行在 PrimitiveFunctions.java 中定义的 double 函数,请调用此 curl 脚本:

curl "http://localhost:8080/double" \
-X POST \
-H "Content-Type: application/json" \
-d '2'

GET Query Parameter Mapping

对于 GET 请求,Funqy HTTP 绑定还具有用于函数输入参数的查询参数映射。只有 bean 样式类和 java.util.Map 可以用于您的输入参数。对于 bean 样式类,查询参数名称映射到 bean 类上的属性。这里有一个简单的 Map 示例:

@Funq
public String hello(Map<String, Integer> map) {
...
}

键值必须是基本类型(char 除外)或 String 。值可以是基本类型(char 除外)、StringOffsetDateTime 或复杂 bean 样式类。对于上述示例,以下是相应的 curl 请求:

curl "http://localhost:8080/a=1&b=2"

hello 函数的 map 输入参数将具有键值对:a1b2

bean 样式类也可以用作输入参数类型。这里有一个示例:

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();
    }
}

属性值可以是除 char 以外的任何基本类型。它也可以是 StringOffsetDateTimeOffsetDateTime 查询参数值必须采用 ISO-8601 格式。

可以使用 HTTP GET 和查询参数对此进行调用:

curl "http://localhost:8080/greet?first=Bill&last=Burke"

在上面的请求中,查询参数名称映射到输入类中对应的属性。

输入类也可以具有嵌套的 bean 类。对上一个示例进行扩展:

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) {
       ...
    }
}

在这种情况下,嵌套值的查询参数使用 . 表示法。例如:

curl "http://localhost:8080/greet?dad.first=John&dad.last=Smith&mom.first=Martha&mom.last=Smith"

java.util.ListSet 也支持作为属性值。例如:

public class Family {
    ...

    List<String> pets;
}

public class MyFunctions {
    @Funq
    public String greet(Family family) {
       ...
    }
}

若要调用 GET 请求,只需多次列出 pets 查询参数即可。

curl "http://localhost:8080/greet?pets=itchy&pets=scratchy"

对于更复杂类型,ListSet 成员必须在 query 参数中具有一个标识符。例如:

public class Family {
    ...

    List<Person> kids;
}

public class MyFunctions {
    @Funq
    public String greet(Family family) {
       ...
    }
}

每个 kids 查询参数都必须标识它们引用的 kid,以便运行时能够找出哪些属性值属于列表中哪些成员。以下是 curl 请求:

curl "http://localhost:8080/greet?kids.1.first=Buffy&kids.2.first=Charlie"

上述 URL 使用值 12 来标识列表的目标成员,但可以使用任何唯一的字符串。

属性也可以是 java.util.Map 。映射的键可以是任何基本类型和 String 。例如:

public class Family {
    ...

    Map<String, String> address;
}

public class MyFunctions {
    @Funq
    public String greet(Family family) {
       ...
    }
}

相应的调用将如下所示:

curl "http://localhost:8080/greet?address.state=MA&address.city=Boston"

如果您的 Map 值是复杂类型,那么只需通过在最后添加要设置的属性来继续表示法即可。

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"