Standalone Web Applications
Functions could be automatically exported as HTTP endpoints.
The spring-cloud-function-web
module has autoconfiguration that
activates when it is included in a Spring Boot web application (with
MVC support). There is also a spring-cloud-starter-function-web
to
collect all the optional dependencies in case you just want a simple
getting started experience.
With the web configurations activated your app will have an MVC
endpoint (on "/" by default, but configurable with
spring.cloud.function.web.path
) that can be used to access the
functions in the application context where function name becomes part of the URL path. The supported content types are
plain text and JSON.
It is important to understand that while SCF provides ability to export Functional beans as REST endpoints it is NOT a replacement for Spring MVC/WebFlux etc. It is primarily to accommodate stateless serverless patterns where you simply want to have some stateless functionality to be exposed via HTTP. |
Method | Path | Request | Response | Status |
---|---|---|---|---|
GET |
/{supplier} |
- |
Items from the named supplier |
200 OK |
POST |
/{consumer} |
JSON object or text |
Mirrors input and pushes request body into consumer |
202 Accepted |
PUT |
/{consumer} |
JSON object or text |
Mirrors input and pushes request body into consumer |
202 Accepted |
DELETE |
/{consumer} |
JSON object or text |
- |
204 NO CONTENT |
POST |
/{function} |
JSON object or text |
The result of applying the named function |
200 OK |
PUT |
/{function} |
JSON object or text |
The result of applying the named function |
200 OK |
GET |
/{function}/{item} |
- |
Convert the item into an object and return the result of applying the function |
200 OK |
As the table above shows the behavior of the endpoint depends on the method and also the type of incoming request data. When the incoming data is single valued, and the target function is declared as obviously single valued (i.e. not returning a collection or Flux
), then the response will also contain a single value.
For multi-valued responses the client can ask for a server-sent event stream by sending Accept: text/event-stream
.
Functions and consumers that are declared with input and output in Message<?>
will see the request headers as message headers, and the output message headers will be converted to HTTP headers.
The payload of the Message will be a body
or empty string if there is no body
or it is null.
When POSTing text the response format might be different with Spring Boot 2.0 and older versions, depending on the content negotiation (provide content type and accept headers for the best results).
See [Testing Functional Applications] to see the details and example on how to test such application.
HTTP Request Parameters
As you have noticed from the previous table, you can pass an argument to a function as path variable (i.e., /{function}/{item}
).
For example, localhost:8080/uppercase/foo
will result in calling uppercase
function with its input parameter being foo
.
While this is the recommended approach and the one that fits most use cases cases, there are times when you have to deal with HTTP request parameters (e.g., localhost:8080/uppercase/foo?name=Bill
).
The framework will treat HTTP request parameters similar to the HTTP headers by storing them in the Message
headers under the header key http_request_param
with its value being a Map
of request parameters, so in order to access them your function input signature should accept Message
type (e.g., Function<Message<String>, String>
). For convenience we provide HeaderUtils.HTTP_REQUEST_PARAM
constant.
Function Mapping rules
If there is only a single function (consumer etc.) in the catalog, the name in the path is optional.
In other words, providing you only have uppercase
function in catalog
curl -H "Content-Type: text/plain" localhost:8080/uppercase -d hello
and curl -H "Content-Type: text/plain" localhost:8080/ -d hello
calls are identical.
Composite functions can be addressed using pipes or commas to separate function names (pipes are legal in URL paths, but a bit awkward to type on the command line).
For example, curl -H "Content-Type: text/plain" localhost:8080/uppercase,reverse -d hello
.
For cases where there is more than a single function in catalog, each function will be exported and mapped with function name being
part of the path (e.g., localhost:8080/uppercase
).
In this scenario you can still map specific function or function composition to the root path by providing
spring.cloud.function.definition
property
For example,
--spring.cloud.function.definition=foo|bar
The above property will compose 'foo' and 'bar' function and map the composed function to the "/" path.
The same property will also work for cases where function can not be resolved via URL. For example, your URL may be localhost:8080/uppercase
, but there is no uppercase
function.
However there are function foo
and bar
. So, in this case localhost:8080/uppercase
will resolve to foo|bar
.
This could be useful especially for cases when URL is used to communicate certain information since there will be Message header called uri
with the value
of the actual URL, giving user ability to use it for evaluation and computation.
Function Filtering rules
In situations where there are more than one function in catalog there may be a need to only export certain functions or function compositions. In that case you can use
the same spring.cloud.function.definition
property listing functions you intend to export delimited by ;
.
Note that in this case nothing will be mapped to the root path and functions that are not listed (including compositions) are not going to be exported.
For example,
--spring.cloud.function.definition=foo;bar
This will only export function foo
and function bar
regardless how many functions are available in catalog (e.g., localhost:8080/foo
).
--spring.cloud.function.definition=foo|bar;baz
This will only export function composition foo|bar
and function baz
regardless how many functions are available in catalog (e.g., localhost:8080/foo,bar
).
Http Headers propagation
By default most request HttpHeaders
are copied into the response HttpHeaders
. If you require to filter out certain headers you can provide the names of those headers using
spring.cloud.function.http.ignored-headers
delimited by comas. For example, spring.cloud.function.http.ignored-headers=foo,bar
.
CRUD REST with Spring Cloud Function
By now it should be clear that functions are exported as REST endpoints and can be invoked using various HTTP methods. In other words a single function could be triggered via GET, POST, PUT etc.
However, it is not always desirable and certainly does not fit the CRUD concept. And while SCF does not support and has no intention of supporting all the features of Spring web stack, the framework does provide support for CRUD mappings where a single function could be mapped to a particular HTTP method(s). It is done via spring.cloud.function.http.<method-name> property.
For example,
spring.cloud.function.http.GET=uppercase;reverse;foo|bar spring.cloud.function.http.POST=reverse spring.cloud.function.http.DELETE=deleteById
As you can see, here we’re mapping functions to various HTTP methods using the same rules as spring.cloud.function.definition
property where “;” allows us to define several functions and “|” signifies function composition.