Files
spring-cloud-function/docs/modules/ROOT/pages/spring-cloud-function/standalone-web-applications.adoc
2024-04-04 11:27:51 +01:00

126 lines
7.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[[standalone-web-applications]]
= 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.
IMPORTANT: 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]]
== 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, `http://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., `http://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]]
== 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]]
== 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]]
== 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 were 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.