Skip to content

Commit

Permalink
Support @HttpExchange for server-side handling
Browse files Browse the repository at this point in the history
  • Loading branch information
OlgaMaciaszek authored and rstoyanchev committed Aug 4, 2023
1 parent 646fd3e commit d1d5b54
Show file tree
Hide file tree
Showing 8 changed files with 668 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
[[webflux-ann-httpexchange]]
= HttpExchange

[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc[See equivalent in the Servlet stack]#

Similarly to
xref:web/webflux/controller/ann-requestmapping.adoc[`@RequestMapping`],
you can use the `@HttpExchange` annotation to map requests to controllers
methods. However, while `@RequestMapping` is only supported on the server side, `@HttpExchange` can be used both to create a server-side mapping and
xref:integration/rest-clients.adoc#rest-http-interface[an HTTP
Interface Client] that allows making requests.

`@HttpExchange` has various attributes to match by URL, HTTP method, and media
types. You can use it at the class level to express shared mappings or at the
method level to narrow down to a specific endpoint mapping.

There are also HTTP method specific shortcut variants of `@HttpExchange`:

* `@GetExchange`
* `@PostExchange`
* `@PutExchange`
* `@DeleteExchange`
* `@PatchExchange`

// TODO
The shortcuts are xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-composed[Custom Annotations] that are provided
because, arguably, most controller methods should be mapped to a specific
HTTP method versus using `@HttpExchange`, which, by default, matches
to all HTTP methods.
An `@HttpExchange` is still needed at the class level to express shared mappings.

The following example has type and method level mappings:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@RestController
@HttpExchange("/persons")
class PersonController {
@GetExchange("/{id}")
public Person getPerson(@PathVariable Long id) {
// ...
}
@PostExchange
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Person person) {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@RestController
@HttpExchange("/persons")
class PersonController {
@GetExchange("/{id}")
fun getPerson(@PathVariable id: Long): Person {
// ...
}
@PostExchange
@ResponseStatus(HttpStatus.CREATED)
fun add(@RequestBody person: Person) {
// ...
}
}
----
======


`@HttpExhange` supports a very similar method signature to `@MessageMapping`,
however, since it needs to be suitable both for requester and responder use,
there are slight differences.

[[webflux-ann-httpexchange-uri-templates]]
== URI patterns
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-uri-templates[See equivalent in the Servlet stack]#

URI patterns resolution support is very similar to the one offered by xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-requestmapping-uri-templates[`@RequestMapping`], with the difference
that while `@RequestMapping` accepts a `String` array as its `value` or `path`
parameter that is used to specify the URI patterns, only a single `String` can be passed
as the `value` of `@HttpExchange`.

[[webflux-ann-httpexchange-contenttype]]
== Consumable Media Types
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-contenttype[See equivalent in the Servlet stack]#

You can narrow the request mapping based on the `Content-Type` of the request,
as the following example shows:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@PostExchange(path = "/pets", contentType = "application/json") // <1>
public void addPet(@RequestBody Pet pet) {
// ...
}
----
<1> Using a `contentType` attribute to narrow the mapping by the content type.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@PostExchange("/pets", contentType = "application/json") // <1>
fun addPet(@RequestBody pet: Pet) {
// ...
}
----
<1> Using a `contentType` attribute to narrow the mapping by the content type.
======

The `contentType` attribute accepts a single `String` as the attribute value.

You can also declare a shared `contentType` attribute at the class level.
Unlike most other request-mapping attributes, however, when used at the
class level, a method-level `contentType` attribute overrides rather than
extends the class-level declaration.

TIP: `MediaType` provides constants for commonly used media types, such as
`APPLICATION_JSON_VALUE` and `APPLICATION_XML_VALUE`.


[[webflux-ann-httpexchange-accept]]
== Producible Media Types
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-accept[See equivalent in the Servlet stack]#

You can narrow the request mapping based on the `Accept` request header and the list of
content types that a controller method produces, as the following example shows:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@GetExchange(path = "/pets/{petId}", accept = "application/json") // <1>
@ResponseBody
public Pet getPet(@PathVariable String petId) {
// ...
}
----
<1> Using an `accept` attribute to narrow the mapping by the content type that
can be served.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@GetExchange("/pets/{petId}", accept = ["application/json"]) // <1>
@ResponseBody
fun getPet(@PathVariable petId: String): Pet {
// ...
}
----
<1> Using an `accept` attribute to narrow the mapping by the content type that
can be served.
======

The `accept` attribute accepts a `String` array as the attribute value.

You can declare a shared `accept` attribute at the class level. Unlike most
other request-mapping attributes, however, when used at the class level,
a method-level `accept` attribute
overrides rather than extends the class-level declaration.

TIP: `MediaType` provides constants for commonly used media types, such as
`APPLICATION_JSON_VALUE` and `APPLICATION_XML_VALUE`.


[[webflux-ann-httpexchange-params-and-headers]]
== Parameters, headers
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-params-and-headers[See equivalent in the Servlet stack]#

You can narrow request mappings based on request parameter and headers
conditions. It is supported for `@HttpExchange` in the same way as in xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-requestmapping-params-and-headers[`@RequestMapping` parameters and headers support].


[[webflux-ann-httpexchange-head-options]]
== HTTP HEAD, OPTIONS
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-head-options[See equivalent in the Servlet stack]#

The support of `HTTP HEAD` and `HTTP OPTIONS` in `@HttpExchange` annotated
controllers is the same xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-requestmapping-head-options[
as in `@RequestMapping` annotated controllers].

[[webflux-ann-httpexchange-composed]]
== Custom Annotations
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-composed[See equivalent in the Servlet stack]#

`@HttpExchange` annotated controllers support the use of xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[composed annotations]
for request mapping. Those are annotations that are themselves meta-annotated
with `@HttpExchange` and composed to redeclare a subset (or all) of the
`@HttpExchange` attributes with a narrower, more specific purpose.

`@GetExchange`, `@PostExchange`, `@PutExchange`, `@DeleteExchange`,
and `@PatcExchange` are examples of composed annotations. They are provided
because, arguably, most controller methods should be mapped to a specific
HTTP method versus using `@HttpExchange`, which, by default,
matches to all HTTP methods. If you need an example of composed annotations,
look at how those are declared.


Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

[.small]#xref:web/webmvc/mvc-controller/ann-methods.adoc[See equivalent in the Servlet stack]#

`@RequestMapping` handler methods have a flexible signature and can choose from a range of
`@RequestMapping` and `@HttpExchange` handler methods have a flexible signature and can choose from a range of
supported controller method arguments and return values.


Loading

0 comments on commit d1d5b54

Please sign in to comment.